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:
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
h1throughh4whenheader.levelis present; a header with no level usesh2. - Rich-text and Markdown lists use native
ul/ol/lielements. 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_labelwhen supplied. Icon buttons use theiraccessibility_labelor text; the two feedback buttons are named frompositive_button.text.textandnegative_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 userole="note". Stabledata-unhandled-*attributes identify fallback content for tests.
Current limitations
- Headings inside a
markdownblock are visually styled but are not HTML heading elements. Use aheaderblock 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 arole="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'sconfirmobject opens arole="alertdialog"before itsonActionfires; denying it leaves the control's new state in place, as the Builder does. Overflow buttons open arole="menu"ofmenuitems 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 witharia-haspopup="dialog": the field or its "Open calendar" trigger opens arole="dialog"calendar (role="grid",aria-current="date"on today,aria-pressedon the pick) where arrows move the cursor, PageUp and PageDown change month, Enter picks, and Escape closes.workflow_buttonis 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.