Unknown blocks and fallbacks
Rendering is tolerant of JSON-compatible runtime data and does not run strict validation first. Slack can add block types before the package knows their shape; an unknown discriminator renders as a labeled fallback instead of being silently omitted.
View payload JSON
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "The next block type does not exist yet:"
}
},
{
"type": "meeting_recap",
"summary": "Q3 planning sync",
"attendees": 14
}
]
}Fallback behavior is not limited to whole blocks. This payload clamps an
out-of-range header level, shows an image placeholder for a slack_file ID
without a URL, renders a zero-total pie state, leaves an unresolved mention and
unknown emoji readable, and shows a labeled fallback for an invented accessory
inside an otherwise usable section:
Clamped to h4
Nothing to plot
View payload JSON
{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Clamped to h4"
},
"level": 9
},
{
"type": "image",
"alt_text": "quarterly chart",
"slack_file": {
"id": "F0123456789"
}
},
{
"type": "data_visualization",
"title": "Nothing to plot",
"chart": {
"type": "pie",
"segments": [
{
"label": "none",
"value": 0
}
]
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Unresolved: <@U9999999999> :not-a-real-emoji:"
},
"accessory": {
"type": "hologram_projector",
"action_id": "beam"
}
}
]
}The fallback keeps a human-readable label in the DOM, tagged with
data-unhandled-block and data-block-type attributes so you can detect or
style degraded content:
document.querySelectorAll("[data-unhandled-block]");Fallbacks below the block level carry their own attributes:
data-unhandled-element (elements and accessories),
data-unhandled-rich-text-container and data-unhandled-rich-text-element
(rich text), and data-unhandled-chart-type (charts).
What degrades, and how
| Input | Behavior |
|---|---|
Unknown block type | Labeled fallback node with data-block-type |
| Unknown element or accessory inside a known block | The block renders; the element becomes a labeled fallback |
| Known block or element with unusable required fields | Usable siblings remain; the malformed part becomes a fallback or empty preview |
| Unknown rich-text container or inline element | Visible text/reference fallback inside the rich text |
Out-of-range presentation values (e.g. header.level: 9) | Clamped to the legal range |
image with a slack_file ID | Alt-labeled placeholder, because a file ID has no renderable URL |
| Image with a missing, unusable, or non-HTTP(S) source | Named placeholder; a valid URL that fails during browser loading remains a failed <img> |
| Unresolved mentions and custom emoji | ID or :shortcode: stays visible (see Resolvers) |
| Empty collections (no rows, no chart data) | Render safely; a zero-total pie chart shows a labeled "No chart data" state |
What throws
Passing a string that fails JSON.parse throws BlockKitInvariantError with
code: "invalid_json". Strict validators throw the same error class for
invalid payloads; rendering itself does not call them.
Resolver and onAction functions are host application code. The renderer does
not catch their errors or convert them to BlockKitInvariantError. Resolver
failures occur while React renders; onAction failures occur in React event
handlers and are reported according to the host's event-error handling. Catch
failures in the callback when the application needs controlled recovery.
When you want strictness
Tolerant rendering shows the payload as-is. For the package's strict checks, run the validators before rendering:
import { parseBlockKitData } from "react-blockkit";
const json = '{"blocks":[{"type":"section","text":{"type":"mrkdwn","text":"hi"}}]}';
const typed = parseBlockKitData(json, "message");Validation enforces the package's strict limits (block counts, text lengths, element placement, nesting), which the renderer deliberately does not. The full rule inventory and the message-input compatibility caveat are in the validation reference.