VPAT
VPAT 2.5 — WCAG 2.1 Edition
Voluntary Product Accessibility Template for ply CSS Framework v1.0.6. Evaluated March 2026 via source code review of SCSS components, compiled CSS analysis, and manual inspection of rendered output. Contact: GitHub Issues .
Scope
Scope and Disclaimers
This VPAT evaluates the ply CSS framework itself — its stylesheets, CSS custom properties, utility classes, and semantic HTML auto-styling. It does not evaluate any specific application built with ply. Standard VPAT terminology is used throughout: Supports, Partially Supports, and Not Applicable.
- ply is a CSS-only framework with zero JavaScript. It provides visual presentation and layout but does not manage DOM structure, ARIA attributes, or dynamic state.
- Application-level conformance (content structure, alternative text, ARIA for custom widgets, form labels, error identification, page titles, language declarations, etc.) is the responsibility of the application developer.
- ply provides the visual infrastructure to support accessible applications, but using ply does not automatically make an application conformant.
-
Color contrast ratios cited below are based on the framework's
default theme tokens. Custom themes created by overriding
--ply-*variables may alter contrast ratios.
Conformance
Table 1: WCAG 2.1 Level A
| Criteria | Conformance | Remarks |
|---|---|---|
| 1.1.1 Non-text Content | Not Applicable |
ply does not generate non-text content. Alternative text for
images, icons, and media is an application-level concern. ply
provides .sr-only to help authors supply
screen-reader-only text.
|
| 1.2.1 Audio-only and Video-only (Prerecorded) | Not Applicable | ply does not include audio or video content. |
| 1.2.2 Captions (Prerecorded) | Not Applicable | ply does not include multimedia content. |
| 1.2.3 Audio Description or Media Alternative (Prerecorded) | Not Applicable | ply does not include multimedia content. |
| 1.3.1 Info and Relationships | Supports |
ply auto-styles semantic HTML elements (
<nav>, <table>, <details>, <dialog>, <code>, <kbd>, <mark>, headings <h1>–
<h6>) so that visual presentation follows
semantic structure. Step indicators use semantic <ol>/<li> with CSS counters for automatic numbering. Dialog sections use semantic <header>/<footer> elements.
|
| 1.3.2 Meaningful Sequence | Supports |
ply's layout system uses CSS flexbox for visual arrangement
without altering DOM order. Reading order follows source order. Multi-step form indicators maintain visual order matching DOM sequence. RTL support via dir="rtl" preserves meaningful reading order through logical property mirroring.
|
| 1.3.3 Sensory Characteristics | Supports | ply does not rely solely on shape, color, size, or visual location to convey information. Color-coded components (alerts, buttons) include text labels as the primary identifier. |
| 1.4.1 Use of Color | Partially Supports | Button and alert variants use color for visual distinction. The framework does not use color as the sole indicator for any framework-level functionality; application developers should provide text labels that convey meaning independently of color. |
| 1.4.2 Audio Control | Not Applicable | ply does not produce audio. |
| 2.1.1 Keyboard | Supports |
ply provides :focus-visible outlines on all
interactive elements: links, buttons, form inputs, nav items,
dropdown items, <summary> elements, and [tabindex]. The .skip-link class
enables keyboard bypass navigation. Sortable table headers (th.sortable) are focusable with :focus-visible. Pagination links receive focus. Dialog close buttons have :focus-visible outlines. All interactions are
CSS-based and do not require pointer-specific input.
|
| 2.1.2 No Keyboard Trap | Supports |
ply is CSS-only and does not create focus traps. Native <dialog> focus trapping is handled by the
browser per the HTML spec.
|
| 2.1.4 Character Key Shortcuts | Not Applicable | ply does not define any keyboard shortcuts. |
| 2.2.1 Timing Adjustable | Not Applicable | ply does not impose time limits. |
| 2.2.2 Pause, Stop, Hide | Supports |
ply respects prefers-reduced-motion: reduce by
disabling all animations and transitions via a universal
selector. Dialog open animations and step indicator transitions are suppressed when reduced motion is preferred. Default animations are limited to subtle hover
transitions and are not auto-playing or continuous.
|
| 2.3.1 Three Flashes or Below Threshold | Supports | ply does not include any flashing or strobing content. Transitions are limited to subtle hover effects. |
| 2.4.1 Bypass Blocks | Supports |
ply provides .skip-link — positioned off-screen
and revealed on focus — enabling keyboard users to bypass
navigation. <nav> is styled semantically,
supporting landmark-based navigation.
|
| 2.4.2 Page Titled | Not Applicable |
Page titles are an application-level concern. ply does not
generate or modify <title> elements.
|
| 2.4.3 Focus Order | Supports |
ply does not manipulate tabindex or alter focus
order. Focus follows DOM source order. Layout classes use
flexbox without order properties that would create
a discrepancy between visual and focus order.
|
| 2.4.4 Link Purpose (In Context) | Not Applicable | Link text content is an application-level concern. ply styles links visually but does not generate link text. |
| 2.5.1 Pointer Gestures | Not Applicable | ply does not require multipoint or path-based gestures. |
| 2.5.2 Pointer Cancellation | Not Applicable | ply is CSS-only and does not bind pointer events via JavaScript. |
| 2.5.3 Label in Name | Not Applicable | Visible labels and accessible names are application-level concerns. |
| 2.5.4 Motion Actuation | Not Applicable | ply does not use device motion for any functionality. |
| 3.1.1 Language of Page | Not Applicable |
The lang attribute on <html> is
an application-level concern.
|
| 3.2.1 On Focus | Supports | ply does not initiate context changes on focus. Focus styles are limited to visual outline indicators. |
| 3.2.2 On Input | Not Applicable | ply is CSS-only and does not perform actions on input. Form submission behavior is an application-level concern. |
| 3.3.1 Error Identification | Not Applicable | Error identification requires JavaScript and is an application-level concern. ply provides visual styling for alerts and form states that can be used to present errors accessibly. |
| 3.3.2 Labels or Instructions | Not Applicable |
Form labels and instructions are application-level concerns.
ply's .form wrapper styles <label> elements but does not generate them.
|
| 4.1.1 Parsing | Not Applicable | Deprecated in WCAG 2.2. ply generates valid CSS. HTML parsing validity is an application-level concern. |
| 4.1.2 Name, Role, Value | Partially Supports |
ply encourages semantic HTML which provides native name, role,
and value to assistive technology. Custom widget ARIA attributes
(e.g., aria-expanded on dropdowns, aria-label on icon buttons) are application-level
concerns that ply cannot enforce via CSS alone.
|
Conformance
Table 2: WCAG 2.1 Level AA
| Criteria | Conformance | Remarks |
|---|---|---|
| 1.3.4 Orientation | Supports | ply does not restrict display to a single orientation. Responsive breakpoints adapt layout to both portrait and landscape viewports. Dialog patterns work in both portrait and landscape orientations. |
| 1.3.5 Identify Input Purpose | Not Applicable |
Input autocomplete attributes are an
application-level concern. ply styles inputs visually but does
not generate or require specific autocomplete values.
|
| 1.4.3 Contrast (Minimum) | Supports |
Light theme: #161616 on #ffffff (~15.4:1). Dark theme: #f4f4f4 on #161616 (~13.9:1). Secondary text: ~7.5:1 light,
~9.6:1 dark. Link colors derive from --ply-btn-default-bg: ~6.1:1 light (#0353e9), ~5.4:1 dark (#4589ff).
Button contrast: btn-primary 6.1:1 light / 7.7:1 dark; btn-secondary 11.6:1 light / 7.6:1 dark;
btn-secondary-outline text uses --ply-color-muted (#767676 light, #8d8d8d dark) for 4.5:1+ in both modes.
Static color buttons use hardcoded WCAG AA values: btn-blue 5.0:1, btn-red 5.0:1, btn-green 5.0:1, btn-yellow 12.5:1 (dark text).
Toast messages use WCAG AA colors (#0f62fe blue, #198038 green, #da1e28 red, #f1c21b yellow with dark text).
Pagination outlined controls, step indicator states, and sort indicators all meet contrast requirements. prefers-contrast: more further increases contrast
to pure black/white.
|
| 1.4.4 Resize Text | Supports |
ply uses relative units (em, rem) for
font sizes and spacing. Text can be resized up to 200% without
loss of content or functionality.
|
| 1.4.5 Images of Text | Not Applicable | ply does not use images of text. All text is rendered as styled HTML text. |
| 1.4.10 Reflow | Supports | ply's responsive grid reflows content to a single column at narrow viewports. Content reflows without requiring horizontal scrolling at 320px CSS width. |
| 1.4.11 Non-text Contrast | Supports |
Form input borders (~3.5:1 light, ~3.1:1 dark), focus
indicators (~4.6:1 light, ~5.5:1 dark), and button backgrounds
all meet the 3:1 minimum. Pagination borders, sort arrow indicators, and step circle borders all meet 3:1 against background. prefers-contrast: more enhances all borders to
pure black or white.
|
| 1.4.12 Text Spacing | Supports |
ply does not set !important on line-height, letter-spacing, word-spacing, or paragraph spacing. The
framework's base line-height: 1.65 already exceeds
the 1.5x criterion.
|
| 1.4.13 Content on Hover or Focus | Supports | ply's hover/focus interactions are limited to visual style changes. The framework does not display additional content on hover or focus that would obscure other content. Sortable table headers show a hover background state. CSS-based dropdown menus can be dismissed by moving focus. |
| 2.4.5 Multiple Ways | Not Applicable |
Providing multiple navigation mechanisms is an
application-level concern. ply provides styling for <nav> elements and navigation components.
|
| 2.4.6 Headings and Labels | Supports |
ply styles heading elements (<h1>–
<h6>) with distinct sizes, weights, and line
heights that create a clear visual hierarchy. Heading content
and descriptive labels are application-level concerns.
|
| 2.4.7 Focus Visible | Supports |
ply provides :focus-visible outlines on all
interactive elements — buttons (btn-primary, btn-secondary,
btn-primary-outline, btn-secondary-outline,
btn-ghost, btn-icon, and all color variants),
links, inputs, nav items,
dropdowns, form controls, modal close buttons, accordion
titles, sortable table headers, pagination links, and dialog close buttons. Consistent indicator: 2px solid outline with 2px
offset.
|
| 3.1.2 Language of Parts | Not Applicable |
The lang attribute on elements with different
languages is an application-level concern.
|
| 3.2.3 Consistent Navigation | Supports |
ply's navigation components (.navbar, .nav-list, .pagination, .breadcrumb, .tabs) provide
consistent visual presentation. Consistent ordering of
navigation items is an application-level concern.
|
| 3.2.4 Consistent Identification | Supports | ply uses consistent class names and visual styling for components with the same function. Buttons, alerts, and form controls render identically wherever used, enforced by CSS custom properties. |
| 3.3.3 Error Suggestion | Not Applicable | Error suggestions require JavaScript logic and are an application-level concern. |
| 3.3.4 Error Prevention (Legal, Financial, Data) | Not Applicable | Error prevention for form submissions is an application-level concern. |
| 4.1.3 Status Messages | Not Applicable |
Status messages and role="status" / aria-live regions require JavaScript and ARIA
attributes, which are application-level concerns. ply provides
visual styling for alerts, toast messages (.message), and notifications.
Use role="status" with aria-live="polite" for informational toasts;
role="alert" with aria-live="assertive" for errors.
|
Built in
Accessibility Features Summary
The following accessibility features are built into the ply CSS framework at the source level, verified by review of the SCSS source files.
Focus Management
-
:focus-visibleoutlines on all interactive elements via_reset.scss(links, buttons,<summary>,[tabindex]) -
Component-specific focus styles in
_buttons.scss,_navigation.scss,_forms.scss,_dropdown.scss,_notifications.scss,_modal.scss,_accordion.scss -
Consistent focus indicator:
2px solid var(--ply-color-focus, #0f62fe)withoutline-offset: 2px -
button:activesuppresses outlines only during click, preserving:focus-visiblefor keyboard users
Color and Contrast
- Light theme:
#161616on#ffffff(~15.4:1) - Dark theme:
#f4f4f4on#161616(~13.9:1) - Secondary text:
#525252light (~7.5:1),#c6c6c6dark (~9.6:1) -
Muted/tertiary text (supplementary content only):
#767676light (~4.5:1),#8d8d8ddark (~4.3:1) -
btn-primaryuses--ply-btn-default-bg/--ply-btn-default-color(6.1:1 light, 7.7:1 dark);btn-secondaryuses--ply-btn-secondary-bg/--ply-btn-secondary-color(11.6:1 light, 7.6:1 dark) -
Static color buttons (
btn-blue,btn-red,btn-green,btn-yellow) use hardcoded WCAG AA values immune to theming -
Toast messages use
--ply-bg-*custom properties for WCAG AA backgrounds;z-index: 110ensures visibility above fixed navigation -
prefers-color-scheme: darkautomatic dark mode with WCAG AA contrast -
prefers-contrast: moresupport — enhances text to pure black/white and borders to maximum contrast - 60+ CSS custom properties for theming, all respecting light/dark modes
Motion and Animation
-
prefers-reduced-motion: reduce— disables all animations and transitions via universal selector in_reset.scss - Dialog open animations and multi-step form transitions respect reduced motion preferences
- Default animations limited to subtle hover transitions (no auto-playing, looping, or flashing content)
Screen Reader Support
-
.sr-only— visually hidden content accessible to assistive technology (clip method) -
.skip-link— visible on focus for keyboard bypass navigation
Semantic HTML Auto-styling
-
<nav>,<table>,<details>,<summary>,<dialog>,<blockquote>,<code>,<pre>,<kbd>,<mark>,<progress>,<meter>,<fieldset>,<legend>,<figcaption>,<abbr>, headings<h1>–<h6> - Native element styling preserves programmatic semantics without requiring wrapper divs or ARIA overrides
Typography
- Relative units (
em,rem) throughout — supports browser text zoom - Responsive font scaling across three breakpoints
-
Typography tokens (
--ply-font-body,--ply-font-heading,--ply-font-mono) for consistent font stacks -
Base
line-height: 1.65exceeds WCAG 1.5x recommendation
Layout
-
Flexbox-based grid does not reorder DOM (no
orderproperty usage that breaks focus or reading order) - Responsive breakpoints reflow to single column at narrow viewports
-
max-width: 100%on images, video, and embedded content for responsive media
Table Interaction
-
Sort indicators on
th.sortablewith keyboard access and:focus-visibleoutlines - Pagination with outlined and solid variants, disabled states, and focus management
- Table filter using input-groups pattern; ghost icon buttons for table actions
Multi-Step Forms
-
Step indicators using semantic
<ol>/<li>with CSS counters for automatic numbering - Completed, active, and error states with accessible contrast ratios
-
Step transitions respect
prefers-reduced-motion: reduce
Dialog Patterns
- Structured layouts with semantic header, body, and footer sections
- Size variants, stacked/nested dialogs with z-index layering, and scrollable body
-
Open animation with
prefers-reduced-motion: reducesupport;:focus-visibleon close button
RTL Support
-
Full layout mirroring via
dir="rtl"— grid, navigation, and form components mirror automatically - Logical property helpers for consistent spacing in both directions
-
.no-rtlopt-out class for elements that should not mirror (e.g., code blocks, phone numbers)
Legacy Components
-
.modaland.accordion-titlenow include:focus-visibleoutlines and theme-aware colors. Applications using these components should still provide ARIA attributes (aria-expanded,aria-controls,role) as these cannot be enforced via CSS.
Guidance
Notes for Application Developers
To build a WCAG 2.1 AA conformant application with ply, developers should:
- Use semantic HTML — ply auto-styles native
elements; avoid
<div>soup - Add a skip link — Place
<a class="skip-link" href="#main">Skip to content</a>as the first focusable element in<body> - Set the page language — Add a
langattribute to<html> - Provide alt text — All
<img>elements needaltattributes; usealt=""only for purely decorative images - Label form controls — Associate
<label>elements with inputs usingfor/id - Add ARIA where needed — Custom widgets (dropdowns,
modals, tabs) need appropriate ARIA roles and states; use
aria-current="page"on active navigation links - Test custom themes — When overriding
--ply-*variables, verify contrast ratios meet WCAG AA (4.5:1 for normal text, 3:1 for large text and UI components) - Use
.sr-only— Provide screen-reader-only text for icon-only buttons and visual-only indicators - Identify errors — Use JavaScript and ARIA to programmatically identify and describe form errors
- Maintain heading hierarchy — Use
<h1>–<h6>in logical order; use.h1–.h6classes on non-heading elements when visual heading style is needed without semantic heading level - Label dialogs — Add
aria-labelledbyto<dialog>elements pointing to the dialog's heading; restore focus to the trigger element on close - Hide decorative icons — Add
aria-hidden="true"to icons that are purely decorative and convey no unique information
Next
Next Steps
Review the full ADA Title II compliance overview for deadline information and framework-level guarantees, or explore the accessibility features reference for implementation details.