<pg-carousel>

Wrap a collecton of elements in this wrapper element and it will automatically provide a functional, accessible carousel.

Features

Usage

Download JS file

Conditionally load the JavaScript only if the <pg-carousel> is present on the page at load:

if (document.querySelectorAll('pg-carousel').length) import('./carousel.min.js');

Load the script as a module in WordPress:

wp_enqueue_script_module( 'pg-carousel', get_theme_file_uri( 'js/pg-carousel.min.js' ), [], filemtime( get_theme_file_path( 'js/pg-carousel.min.js' ) ) );

Content

Required content
Flow content.
Note that all direct children elements will be turned into slides - any non-slide additions to this wrapper element should be done after the custom element is defined.

Attributes

Name Description Default
aria-labelledby Required. ID reference for an element containing the accessible name for region containing the carousel (e.g. a heading element). undefined
data-autocarousel ID reference for a <template> element containing the markup for the play/pause button. See below. undefined
data-autoplay When present, configures the carousel to auto-advance. undefined
data-controlslabel Label for the controls wrapper element (for translation purposes). Slider controls
data-markerlabel Each marker/indicator receives an accessible name indicating its one-based index in the carousel. This string, which should contain {current} and {total} literally, is used for translation purposes. Show slide {current} of {total}
data-markers When present, outputs markers/indicators to show how many slides are present and which is active.
Optionally, when set to buttons, outputs interactive markers/indicators.
undefined
data-nextbtn ID reference for a <template> element containing the markup for the next button. See below. undefined
data-prevbtn ID reference for a <template> element containing the markup for the previous button. See below. undefined
data-slidelabel Each slide receives an accessible name indicating its one-based index in the carousel. This string, which should contain {current} and {total} literally, is used for translation purposes. {current} of {total}
data-start Label for the play/pause button for auto-advancing carousels when the advancement is paused (for translation purposes). Start slide rotation
data-stop Label for the play/pause button for auto-advancing carousels when the advancement is playing (for translation purposes). Stop slide rotation

Properties

Name Description
slideCount Total number of slides.
activeSlide 1-based index of currently active slide.

Events

Name Description
pg-carousel-change Fires whenever the active slide is updated.

Templates

Previous Button

If defined, the component can make use of a templated <button> to override the included, barebones previous button. The defined template should be a <button> element with a class of prevbtn.

Be sure to give this button an accessible name.

<template id="prevbtn">
	<button type="button" class="prevbtn">
		<svg width="44" height="44" aria-hidden="true">
			<path fill="none" stroke="currentcolor" d="m21.22 29-7.021-7 7.021-7M14 22h16"/>
		</svg>
		<span class="screen-reader-text">Previous slide</span>
	</button>
</template>

Next Button

If defined, the component can make use of a templated <button> to override the included, barebones next button. The defined template should be a <button> element with a class of nextbtn.

Be sure to give this button an accessible name.

<template id="nextbtn">
	<button type="button" class="nextbtn">
		<svg width="44" height="44" aria-hidden="true">
			<path fill="none" stroke="currentcolor" d="m22.78 15 7.021 7-7.021 7M30 22H14"/>
		</svg>
		<span class="screen-reader-text">Next slide</span>
	</button>
</template>

Play/Pause Button

If defined, the component can make use of a templated <button> to override the included, barebones play/pause button. The defined template should be a <button> element with a class of playbtn.

For styling purposes, descendents of the <button> that should only be displayed when the video is paused should be given a class of play and those that should only be displayed when the video is playing should be given a class of pause.

<template id="autocarousel">
	<button type="button" class="playbtn">
		<svg width="30" height="30" aria-hidden="true">
			<circle cx="15" cy="15" r="15"/>
			<path class="play" fill="#fff" d="m20 15-7.5 4.33v-8.66z"/>
			<path class="pause" fill="#fff" d="M17.75 19h-1v-8h1zm-4.5-8h-1v8h1z"/>
		</svg>
	</button>
</template>

Style

No additional CSS is required beyond that called for by the overall page design. That said, it is often likely that the non-active slides should be somehow hidden (or less prominent). These inactive slides can be wholesale targeted based on the presense of the aria-hidden="true" attribute.

Examples

Default Appearance (Image Carousel)

Utilizes default, unstyled previous/next buttons.

The following sample styles are applied to the component above.

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}
Default Appearance (Content Carousel)

Utilizes default, unstyled previous/next buttons.

A
B
C
D
E
F

The following sample styles are applied to the component above.

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}
pg-carousel:defined .slide-wrap [role="group"] {display: grid; place-items: center;}
pg-carousel:defined .slide-wrap [role="group"] > * {grid-area: 1 / 1; font-size: 5rem;}
Custom Previous/Next Buttons (Image Carousel)

Utilizes the previous/next buttons defined within a <template> element whose [id] is passed via the [data-prevbtn] and [data-nextbtn] attributes on the component.

The following sample styles are applied to the component above. (You will need to provide your own reset for the <button> elements themselves.)

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}
Custom Controls Wrapper Label

Utilizes a translated string for the controls wrapper element, defined by the data-controlslabel attribute on the component. (Note that this string is used within the controls wrapper element's aria-label attribute.)

The following sample styles are applied to the component above. (You will need to provide your own reset for the <button> elements themselves.)

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}
Custom Slides Label

Utilizes a translated string for each slide element, defined by the data-slidelabel attribute on the component. (Note that this string is used within each slide element's aria-label attribute.)

The following sample styles are applied to the component above. (You will need to provide your own reset for the <button> elements themselves.)

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}
With Indicators (Image Carousel)

Non-interactive indicators can be added with the [data-markers] attribute.

The following sample styles are applied to the component above.

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}
pg-carousel:defined .pg-carousel-markers {display: flex; gap: .5rem; padding-left: 0;}
pg-carousel:defined .pg-carousel-markers li {width: 1rem; height: 1rem; border: 1px solid; border-radius: 50%; list-style: none;}
pg-carousel:defined .pg-carousel-markers [aria-disabled="true"] {background-color: red;}
Custom Indicator Labels (Image Carousel)

Utilizes a translated string for each marker/indicator element, defined by the data-markerlabel attribute on the component. (Note that this string is used within each marker/indicator element's aria-label attribute.)

The following sample styles are applied to the component above.

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}
pg-carousel:defined .pg-carousel-markers {display: flex; gap: .5rem; padding-left: 0;}
pg-carousel:defined .pg-carousel-markers li {width: 1rem; height: 1rem; border: 1px solid; border-radius: 50%; list-style: none;}
pg-carousel:defined .pg-carousel-markers [aria-disabled="true"] {background-color: red;}
With Button Indicators (Image Carousel)

Interactive indicators can be added with the [data-markers="buttons"] attribute.

The following sample styles are applied to the component above. (You will need to provide your own reset for the <button> elements themselves.)

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}
pg-carousel:defined .pg-carousel-markers {display: flex; gap: .5rem; padding-left: 0;}
pg-carousel:defined .pg-carousel-markers li {width: 1rem; height: 1rem; border: 1px solid; border-radius: 50%; list-style: none;}
pg-carousel:defined .pg-carousel-markers [aria-disabled="true"] {background-color: red;}
Custom Button Indicator Labels (Image Carousel)

Utilizes a translated string for each marker/indicator element, defined by the data-markerlabel attribute on the component. (Note that this string is used within each marker/indicator element's aria-label attribute.)

The following sample styles are applied to the component above. (You will need to provide your own reset for the <button> elements themselves.)

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}
pg-carousel:defined .pg-carousel-markers {display: flex; gap: .5rem; padding-left: 0;}
pg-carousel:defined .pg-carousel-markers li {width: 1rem; height: 1rem; border: 1px solid; border-radius: 50%; list-style: none;}
pg-carousel:defined .pg-carousel-markers [aria-disabled="true"] {background-color: red;}
Auto-Advancing with Default Appearance (Image Carousel)

Add auto-advancing functionality to the carousel by adding the [data-autoplay] attribute. The auto-play functionality will stop automatically if the user hovers over the slides or focuses within the component.

The following sample styles are applied to the component above.

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}
Auto-Advancing with Custom Play/Pause Buttons (Image Carousel)

Utilizes the play/pause button defined within a <template> element whose [id] is passed via the [data-autoplay] attribute on the component.

The following sample styles are applied to the component above. (You will need to provide your own reset for the <button> elements themselves.)

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}
pg-carousel:defined :is(.playbtn[aria-label="Start slide rotation"] .pause, .playbtn[aria-label="Stop slide rotation"] .play) {display: none;}
Auto-Advancing with Custom Play/Pause Button Labels (Image Carousel)

Utilizes translated strings for "Start slide rotation" and "Stop slide rotation", defined by the data-start and data-stop attributes on the component, respectively. (Note that these strings are used within the play/pause button's aria-label attribute.)

The following sample styles are applied to the component above.

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}
Custom Indicator Counts (Image Carousel)

Utilizing the activeSlide & slideCount properties alongside the pg-carousel-change event, a numeric status can be added.

The following sample styles are applied to the component above.

pg-carousel:defined .slide-wrap {display: grid;}
pg-carousel:defined .slide-wrap * {grid-area: 1 / 1;}
pg-carousel:defined .slide-wrap [aria-hidden="false"] {z-index: 1;}

The following additional sample scripts are applied to the component above.

customElements.whenDefined('pg-carousel').then(() => {

	const theCarousel = [some reference to this carousel component];

	const div = document.createElement('div');
	div.classList.add('status');
	div.textContent = `${theCarousel.activeSlide} of ${theCarousel.slideCount}`;
	theCarousel.appendChild(div);

	theCarousel.addEventListener('pg-carousel-change', () => {
		theCarousel.querySelector('.status').textContent = `${theCarousel.activeSlide} of ${theCarousel.slideCount}`;
	});

});

Tests

Empty Component

The required child elements are not present.

Result: a console error is thrown.

Inaccessible Component

The required [aria-labelledby] attribute is not set to define an accessible name for the component.

Result: a console error is thrown.

Improper Prevous Button Template

The referenced previous button template does not contain a <button> element with a class of prevbtn.

Note that the component has a aria-labelledby attribute set to the id attribute of the above <h2> and <summary> elements.

Result: silently falls back to the default previous button template.

Improper Next Button Template

The referenced next button template does not contain a <button> element with a class of nextbtn.

Note that the component has a aria-labelledby attribute set to the id attribute of the above <h2> and <summary> elements.

Result: silently falls back to the default next button template.

Improper Play/Pause Button Template

The referenced play/pause button template does not contain a <button> element with a class of playbtn.

Note that the component has a aria-labelledby attribute set to the id attribute of the above <h2> and <summary> elements.

Result: silently falls back to the default play/pause button template.


Back