WebProCMS ships its sliders/carousels and accordions (FAQ rows and anywhere else they appear) with WCAG 2.1 AA-friendly keyboard support and ARIA semantics built in. Site owners don't have to know what aria-expanded or tabindex means to get screen-reader-friendly, keyboard-navigable widgets — every design library row built on these components inherits the behavior automatically.
Sliders & carousels
Every slider in the design library — image sliders, testimonial sliders, hero sliders, feature carousels, and the rest — handles keyboard focus correctly out of the box.
- Inactive slides are not keyboard-reachable. When a slide isn't the active one it's fully hidden (
display:none), which removes it and everything inside it from the tab order. A keyboard user tabbing through the page never lands on a link or button buried in a slide they can't see. Off-screen slides also start hidden in the raw HTML, so this holds even before JavaScript loads. - Arrow keys move between slides. Left/Right arrow keys advance and rewind the active slider.
- Labelled controls. Previous/Next arrows and the dot navigation each carry descriptive
aria-labels ("Previous slide", "Go to slide 3") so assistive tech announces what they do, and the active dot carriesaria-currentso the position is announced too. - Announced as a carousel. The slider root is a
role="region"landmark witharia-roledescription="carousel", and each slide is arole="group"witharia-roledescription="slide"and an "N of M" label — screen readers identify the widget and the visitor's position in it (WAI-ARIA carousel pattern). - Slide changes are announced only when the visitor is driving. The slide container's
aria-liveispolitewhile the slider is stopped (manual navigation announces the new slide) andoffwhile autoplay is running, so an auto-rotating slider never spams the screen reader. - Autoplay pauses on hover and only runs when there's more than one slide, so it never traps or distracts when there's nothing to rotate.
- Native-scroll carousels stay fully reachable. The multi-card "scroller" style sliders (where several cards are visible and you swipe/scroll horizontally) keep every card visible and tabbable by design — nothing is hidden, so nothing is unreachable.
The shared slider component lives in resources/views/components/dl/slider.blade.php (with dl/slide.blade.php for slot-mode slides). Both the <x-dl.slider> + <x-dl.slide> pattern and the standalone custom-x-data slider rows hide inactive slides with x-show (→ display:none), so the no-tab-into-hidden-slides guarantee is structural, not per-row.
Accordions (FAQ rows and beyond)
Every accordion built on the shared <x-dl.accordion> / <x-dl.accordion-item> components — the FAQs Accordion and FAQs Search Accordion design library rows, plus the FAQ shortcode/blog accordion — follows the WAI-ARIA Authoring Practices accordion pattern.
Keyboard navigation
With focus on any accordion header:
| Key | Action |
|---|---|
| Enter / Space | Expand or collapse the focused section (native button behavior) |
| Down Arrow | Move focus to the next header (wraps from last to first) |
| Up Arrow | Move focus to the previous header (wraps from first to last) |
| Home | Move focus to the first header |
| End | Move focus to the last header |
The arrow/Home/End keys move focus only — they never expand a section, matching the APG spec — and they call preventDefault() so Up/Down don't also scroll the page out from under the user.
Screen-reader semantics
aria-expandedon each header button flips betweentrueandfalseas the section opens and closes, so assistive tech announces "expanded" / "collapsed".aria-controlslinks each header to the panel it toggles, and the panel carriesrole="region"+aria-labelledbypointing back at its header — so a screen reader can jump from a header to its answer and back, and announces the answer region with the question as its label.type="button"on every header so an accordion placed inside a form never accidentally submits it.- Decorative chevrons are
aria-hidden="true", so screen readers don't read a meaningless "image" between every question.
The header/panel IDs are generated automatically and are unique per accordion instance on the page, so two accordions on one page never collide.
What this means for your users
- Keyboard-only visitors can operate every slider and accordion without a mouse.
- Screen-reader users hear meaningful labels and state ("Frequently asked questions, button, collapsed") instead of bare, unlabelled controls.
- You can't accidentally ship an inaccessible FAQ or carousel — the behavior is baked into the shared components, so it can't be "forgotten" on a per-row basis.
For developers
The accessibility behavior is implemented in the shared components, not copied into each row template, so it propagates to every existing page automatically (page blades reference <x-dl.accordion-item> / <x-dl.slider>, which resolve to the shared components at render time):
resources/views/components/dl/accordion.blade.php— addsdata-accordion-rootto the wrapper.resources/views/components/dl/accordion-item.blade.php— renders the header button (type,id,aria-controls, reactivearia-expanded, the fourx-on:keydownhandlers,data-accordion-header) and the panel (id,role="region",aria-labelledby).resources/views/components/faq-accordion.blade.php— the same treatment for the FAQ shortcode/blog accordion.resources/js/public.js— defineswindow.dlAccordionNav(headerEl, dir), the focus-mover called by the keydown handlers. It scopes to the nearest[data-accordion-root]and moves focus among[data-accordion-header]buttons. It's loaded on the public site; in the editor preview iframe (which doesn't loadpublic.js) the keydown handlers no-op gracefully and expand/collapse still works.
Any new slider or accordion design library row built on the standard <x-dl.slider> / <x-dl.slide> / <x-dl.accordion> / <x-dl.accordion-item> components inherits all of this for free — there is nothing extra to wire up per row. New accordion rows must use <x-dl.accordion-item> for each item (not a hand-rolled <button> + panel) to get the keyboard nav and ARIA. New slider rows must hide inactive slides with x-show (or use the native-scroll pattern) rather than translating still-displayed slides off-screen, so hidden slides stay out of the tab order.
For the design library these rows come from, see design-library.md. For accessible header/menu navigation, see accessible-navigation.md; for the automated audit tool, see accessibility-scanner.md.