Validation

Rendering is deliberately tolerant; validation is deliberately strict. The validators check a payload against Slack's documented acceptance rules (limits, required fields, element placement, nesting) and throw a BlockKitInvariantError pointing at the first violation. They run without React, so they work in Node scripts, tests, and server code:

import { assertBlockKitData, parseBlockKitData } from "react-blockkit";

const unknownPayload: unknown = { blocks: [] };
const json = '{"blocks":[]}';

assertBlockKitData(unknownPayload, "message");
const typed = parseBlockKitData(json, "message");

Functions

FunctionSignatureUse
parseBlockKitData(input: BlockKitInput, surface?: BlockKitSurface) => BlockKitDataParse a JSON string or validate a block-shaped input; returns the typed payload. For unknown values, use assertBlockKitData
assertBlockKitData(value: unknown, surface?, path?) => asserts value is BlockKitDataValidate a full payload in place
assertRenderableBlock(value: unknown, surface?, path?) => asserts value is RenderableBlockValidate a single block of any type
assertBlockType(value: unknown, expected: RenderableBlock["type"], surface?, path?) => voidValidate a block and require a specific type
assertRichTextBlockData(value: unknown, path?) => voidValidate one rich_text block
assertTextObjectData(value: unknown, path?, max?) => voidValidate a TextObject with an optional length limit
assertImageElementData(value: unknown, path?) => voidValidate an image element
assertInteractiveElementData(value: unknown, path?) => voidValidate an interactive element
blocksOf(data: BlockKitData) => readonly RenderableBlock[]Normalize { blocks } or a bare array to the block list

surface defaults to "message" and path to a sensible root ("data", "block", "element", "text"). The path parameter only affects error messages. Pass your own when validating a fragment of a larger document.

What gets checked

  • Message/view block-count limits and duplicate block_id detection
  • Required fields, type discriminators, string lengths, and per-block element limits
  • Legal accessory, input, and action element placement
  • Rich-text nesting and preformatted/list constraints
  • Table shape, cell types, row/column limits, and aggregate text budgets
  • Data-table header, row width, page size, and row-header invariants
  • Chart category/series/point consistency
  • Card, carousel, container, task-card, and plan constraints
  • Surface compatibility, listed in full below

Surface compatibility

Thirteen block types are legal on some surfaces and not others. assertBlockKitData throws surface_mismatch when one appears on the wrong surface:

Legal surfaceBlocks
message onlycard, carousel, container, context_actions, data_table, data_visualization, file, markdown, plan, table, task_card
modal onlyalert
modal or homeinput

Every other block validates on all three surfaces. Rendering ignores surface entirely; see Rendering messages.

BlockKitInvariantError

Every validation failure throws this error class, as does the renderer's own malformed-JSON case:

import { BlockKitInvariantError, parseBlockKitData } from "react-blockkit";

const payload = { blocks: [] };

try {
  parseBlockKitData(payload, "modal");
} catch (error) {
  if (error instanceof BlockKitInvariantError) {
    error.code; // "limit_exceeded"
    error.path; // "data.blocks[2].text.text"
    error.message; // "data.blocks[2].text.text: must contain at most 3000 characters"
  }
}
PropertyTypeMeaning
codeBlockKitInvariantCodeStable machine-readable failure category
pathstringJSON path to the offending value, in Slack payload notation
messagestring"<path>: <description>"

Error codes

CodeRaised when
invalid_jsonString input fails JSON.parse
invalid_typeA value has the wrong JavaScript type
missing_fieldA required field is absent
invalid_valueA value is present but illegal (empty string, bad discriminator, out-of-range number)
limit_exceededA Slack length, count, or size limit is exceeded
surface_mismatchA block is not allowed on the validated surface
duplicate_idTwo blocks share a block_id
unsupported_blockA block type is not in the supported inventory
unsupported_elementAn element type is not legal in its position