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 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 menuitems 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.