@octopusdeploy/design-system-components
Version:
The design systems component library.
71 lines (49 loc) • 3.04 kB
Markdown
# Accessibility Patterns
## accessibleName
Components that have no visible label require an `accessibleName` prop to provide an accessible
name for screen readers. In these cases, the component's TypeScript interface enforces
`accessibleName` as required. In some cases we may have been inconsistent and we may have another
prop such as `ariaLabel` or even `aria-label` exposed directly. Always look at the component
props to determine this as we never spread props onto underlying elements.
**Always provide `accessibleName` when:**
- Using `IconButton` without a visible label
- Using `Switch` without a `label` prop
- Using `CheckboxNew` without a `label` prop
```tsx
// IconButton — accessibleName is always required
<IconButton accessibleName="Delete deployment" icon={<DeleteIcon />} onClick={handleDelete} />
// Switch without a label — accessibleName is required
<Switch accessibleName="Enable notifications" value={enabled} onChange={setEnabled} />
// Switch with a label — accessibleName is optional (label provides the accessible name)
<Switch label="Enable notifications" value={enabled} onChange={setEnabled} />
// CheckboxNew with a label — accessibleName is optional (label provides the accessible name)
<CheckboxNew label="Enable notifications" value={enabled} onChange={setEnabled} />
// CheckboxNew without a label — accessibleName is required
<CheckboxNew accessibleName="Enable notifications" value={enabled} onChange={setEnabled} />
```
## Don't suppress type errors on accessibleName
If TypeScript reports a missing `accessibleName`, provide one. Do not cast to `any` or suppress
the error — the requirement exists for a reason.
## Semantic HTML within components
Design system components render appropriate semantic HTML internally. Do not override the rendered
element type using props like `component="div"` unless the component explicitly supports it and
the use case is documented.
## Form field labels
All form field components (`TextField`, `Select`, `NumberField`, etc.) require a `label` prop. This label is rendered visibly and associated with the input for accessibility.
Do not omit labels or attempt to hide them with custom CSS.
## ARIA props
Some components expose limited ARIA props (`aria-controls`, `aria-haspopup`, `aria-expanded`) for
specific interactive patterns (e.g. a Button that controls a panel). Only pass these when the
component explicitly documents them and the pattern requires it.
Do not add arbitrary `aria-*` props by spreading onto design system components — the components
manage their own ARIA semantics and usually don't spread onto the underlying element.
## Testing accessibility
New components in the design system are tested with `vitest-axe`. When writing tests for pages or
features, run axe checks to catch accessibility violations:
```tsx
import { axe } from "vitest-axe";
it("has no accessibility violations", async () => {
const { container } = render(<MyComponent />);
expect(await axe(container)).toHaveNoViolations();
});
```