# 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();
});
```
