# Accessibility

`react-blockkit` preserves useful semantics for a Block Kit preview, but it
does not turn Slack payloads into a complete application interface. Treat the
renderer as preview content and test the surrounding workflow with the
assistive technologies your application supports.

## Name each preview

`<BlockKit />` renders a `role="article"` root named `"Slack Block Kit
preview"` by default. Give it a specific name when a page has multiple
previews or when the surrounding heading does not explain the content:

```tsx
import { BlockKit, type BlockKitInput } from "react-blockkit";

export function ApprovalPreview({ data }: { data: BlockKitInput }) {
  return <BlockKit aria-label="Approval request from the deployment bot" data={data} />;
}
```

The custom `aria-label` replaces the default root name. `className`, `theme`,
and `surface` do not change that accessible name.

## Semantics the renderer supplies

- Header blocks use `h1` through `h4` when `header.level` is present; a header
  with no level uses `h2`.
- Rich-text and Markdown lists use native `ul`/`ol`/`li` elements. Markdown
  task markers are disabled, named checkboxes.
- Table and data-table blocks use table, row, column-header, and row-header
  semantics. Data-table captions are available to assistive technology.
- HTTP(S) and `mailto:` links use anchors. Unsupported schemes and
  control-bearing URLs remain readable text instead of becoming links.
- Images use a nonblank `alt_text`, then an available title, then `"Image
  without description"` as their accessible name. A missing, unusable, or
  non-HTTP(S) source renders a named placeholder. A valid URL that later fails
  to load remains the browser's failed `<img>`; the renderer does not replace
  network failures with its placeholder.
- Charts expose their title as a named `role="img"` and keep legends visible.
- Buttons, selects, choice groups, and inputs use native controls where the
  preview behavior maps to one. An input block's visible label names its
  control, including a control-specific fallback when that label is blank.
- Button elements use `accessibility_label` when supplied. Icon buttons use
  their `accessibility_label` or text; the two feedback buttons are named from
  `positive_button.text.text` and `negative_button.text.text`.
- Decorative icons are hidden from assistive technology.
- Unknown image-shaped blocks with an accessible image name use `role="img"`;
  other unknown whole blocks use `role="note"`. Stable `data-unhandled-*`
  attributes identify fallback content for tests.

## Current limitations

- Headings inside a `markdown` block are visually styled but are not HTML
  heading elements. Use a `header` block when heading navigation matters in
  the preview.
- An input block's hint is visible but is not associated with its control
  through `aria-describedby`. Do not use the preview as the only form UI for a
  production workflow.
- Chart graphics have a title-level accessible name, not a full textual
  description of every plotted value. Provide adjacent data or a table when
  users must inspect exact values.
- Selects and time pickers are search-selects like Slack's: a text input with
  `role="combobox"` (`aria-expanded`, `aria-activedescendant`) over the
  painted pill, token field, or summary button, and a `role="listbox"` popover
  that opens on focus or click, filters as you type, and closes on Enter,
  Escape, Tab, or an outside press. A multi-select in a section accessory or
  actions block is a summary button (`aria-haspopup="dialog"`) that opens
  Slack's picker dialog (`role="dialog"`, `aria-modal`) holding the same
  token field, with Cancel and Confirm. An element's `confirm` object opens a
  `role="alertdialog"` before its `onAction` fires; denying it leaves the
  control's new state in place, as the Builder does. Overflow buttons open a `role="menu"` of
  `menuitem`s with arrow-key focus movement. Workspace-backed selects (users,
  channels, conversations, external) list a single stand-in option because
  the preview cannot query Slack.
- Date pickers (and the `datetimepicker`'s date half) are combobox fields
  with `aria-haspopup="dialog"`: the field or its "Open calendar" trigger
  opens a `role="dialog"` calendar (`role="grid"`, `aria-current="date"` on
  today, `aria-pressed` on the pick) where arrows move the cursor, PageUp and
  PageDown change month, Enter picks, and Escape closes. `workflow_button` is
  display-only. None of the controls reproduce Slack network behavior.
- Resolvers may return any React node. Your resolver is responsible for the
  accessibility of custom avatars, links, or interactive content it returns.

## Interaction guidance

`onAction` reports local browser interactions only. It does not submit to
Slack, announce application state changes, or move focus. If an action updates
content outside the preview, the host application should provide the
appropriate status announcement and focus behavior.

For a read-only preview, omit `onAction` unless interaction is part of the
demonstration. For an application workflow, build purpose-specific controls
around the payload and use the renderer as the visual preview.
