Accessibility
How WidgetCore meets accessibility requirements — the combobox pattern, ARIA roles, live regions, working without JavaScript, FAQ semantics, reduced motion, contrast and an audit checklist.
Accessibility in this plugin is not an extra layer: the markup, the keyboard behaviour and the ARIA attributes are built into every widget from the start. This page explains what is already handled and what you should check when you customise the output.
Live Search widget
The combobox pattern
The field follows the WAI-ARIA combobox pattern:
| Element | Attribute | Meaning |
|---|---|---|
| The input | role="combobox" | Announced as a combined field and list |
| The input | aria-expanded="true/false" | Whether the results panel is open |
| The input | aria-controls="…-list" | The id of the results list |
| The input | aria-autocomplete="list" | Suggestions come from a list |
| The input | aria-activedescendant="…" | The currently highlighted result |
| The results list | role="listbox" | A selectable list |
| Each result | role="option" | A selectable item |
| The selected result | aria-selected="true" | The highlighted option |
Label and accessible name
Every field has an accessible name: a visible <label> when there is room, otherwise aria-label. The panel has aria-label too, and the results list is associated with the field through aria-controls.
Live regions
Two live regions keep screen readers informed without stealing focus:
| Region | aria-live | Announces |
|---|---|---|
| The status text | polite | “8 results found.”, “No results found.” |
| The page counter | polite | “Page 2 of 5” |
The results list itself is not a live region: announcing every list change would be noisy, so only the count is announced.
Working without JavaScript
The markup contains a real <form> that submits with GET to the site root:
<form class="wgcr-search-form" role="search" method="get" action="https://example.com/">
<input type="search" name="s" class="wgcr-search-field" autocomplete="off">
<input type="hidden" name="post_type" value="post">
<button type="submit" class="wgcr-search-submit">Search</button>
</form>
Without JavaScript the submit button still works and the visitor lands on the theme's native search results page. This means the widget never becomes a dead end for assistive technology or for a visitor with scripts disabled.
FAQ widget
Semantic structure
| Element | Markup | Notes |
|---|---|---|
| The question | A <button type="button"> inside a heading tag | The heading level is a control (H2/H3/H4/DIV) |
| The answer | <div role="region" aria-labelledby="…"> | A navigable landmark region |
| The state | aria-expanded="true/false" on the button | Announced by screen readers |
| The connection | aria-controls and aria-labelledby | Unique per widget instance and item |
| The icon | aria-hidden="true" on the SVG | Decorative only |
Closed state and focus
A closed answer is not merely visually hidden — it also leaves the tab order:
.wgcr-faq-a {
overflow: hidden;
max-height: 0;
visibility: hidden;
}
.wgcr-faq-item.open .wgcr-faq-a {
visibility: visible;
}
Using visibility (rather than only max-height) guarantees that links inside a closed answer cannot receive focus, so keyboard users never tab into invisible content.
Structured data
With the “FAQ schema” control on, the widget prints FAQPage JSON-LD. Two rules keep it valid:
- Only items with both a question and an answer are included.
- Only the first FAQ widget on a page prints schema, avoiding duplicate markup.
Reduced motion
All widgets respect prefers-reduced-motion:
@media (prefers-reduced-motion: reduce) {
.wgcr-faq-a,
.wgcr-faq-ic svg,
.wgcr-search-panel,
.wgcr-search-item {
transition: none !important;
animation: none !important;
}
}
| Widget | With reduced motion |
|---|---|
| FAQ | Items open and close instantly; the icon does not rotate with a transition |
| Live Search | The panel appears without a fade; infinite scroll still works |
The behaviour stays complete — only the animation is removed. Nothing is hidden or disabled.
Colour contrast
The default palette was chosen for readable contrast:
| Pair | Ratio | Level |
|---|---|---|
Result title (#0f172a) on white | Above 15:1 | AAA |
Excerpt (#64748b) on white | About 4.8:1 | AA |
Placeholder (#94a3b8) on white | About 2.9:1 | Decorative text only |
FAQ question (#1F2937) on the card | Above 13:1 | AAA |
FAQ answer (#6B7280) on the card | About 5.0:1 | AA |
The focus ring uses a 2px outline in the accent colour with outline-offset, giving at least 3:1 contrast against both the light and the dark backgrounds.
Text direction and layout
All layout rules use logical properties, so right-to-left and left-to-right both work from the same stylesheet:
| Logical property | Instead of |
|---|---|
inset-inline-start / inset-inline-end | left / right |
margin-inline / padding-inline | margin-left / padding-right |
border-inline-start | border-left |
text-align: start | text-align: left |
The icon position, the panel alignment and the pagination order therefore flip correctly on an RTL site without a second stylesheet.
Markup when customising
If you build a custom Elementor template for results, keep these attributes:
| Keep | Why |
|---|---|
role="option" on each result | So aria-activedescendant keeps working |
| A focusable link inside the result | So Enter opens the result |
| Text alternatives for images | A meaningful alt, or alt="" when decorative |
| The heading level of the title | So the results fit the page outline |
The plugin wraps whatever your template prints, so the list roles stay intact; but a result with no link cannot be opened from the keyboard.
Publishing checklist
Test with the keyboard only
Tab through the field, open results with ArrowDown and Enter, close with Escape.
Test with a screen reader
Check that the field name, the result count and the FAQ state are announced.
Test without JavaScript
The search form must still submit and the FAQ must still open (details/summary fallback or the CSS cap).
Check contrast
Every text pair you changed should meet at least 4.5:1.
Check reduced motion
Enable the OS setting and confirm nothing animates.
Validate the schema
Run the page through the Rich Results Test.
Keyboard details for each widget are on the keyboard shortcuts page.