Skip to content
Block Kit for React
Esc
↑↓navigate↵open⌘Jpreview
On this page

Validation

The checks Slack's client runs on a modal before view_submission fires, and how to trigger or override them.

Before a modal’s view_submission ever reaches your app, Slack’s own client checks every input block: is it filled in when required, is the text within length limits, is the number in range, is the email or URL well-formed. @nkootstra/block-kit runs the identical checks client-side, so onSubmit only ever sees a submission that would have passed Slack’s client too.

Your AppAPP

Try submitting the modal above without an email: the error appears under the field, exactly like Slack’s own client, and onSubmit never fires.

What gets checked

PropType
required?any input element

An input block without optional: true must have a non-empty value.

Typeany input element
min_length / max_length?plain_text_input

Character count bounds.

Typeplain_text_input
email format?email_text_input

Basic something@something shape, no spaces.

Typeemail_text_input
url format?url_text_input

Must parse as an http:// or https:// URL.

Typeurl_text_input
number format?number_input

Must parse as a number; a whole number unless is_decimal_allowed is set.

Typenumber_input
min_value / max_value?number_input

Numeric bounds.

Typenumber_input

An empty rich_text_input (a rich_text value whose sections hold no actual text: no words, only an empty paragraph) counts as empty for the required check, the same way Slack treats it.

Messages

Every message comes from VALIDATION_MESSAGES, exported so you can read (or override, in your own copy) Slack’s exact client-side wording:

import { VALIDATION_MESSAGES } from "@nkootstra/block-kit";

VALIDATION_MESSAGES.required;
// "Please complete this required field."
VALIDATION_MESSAGES.minLength(3);
// "Please enter at least 3 characters."
VALIDATION_MESSAGES.maxValue("100");
// "Please enter a number less than or equal to 100."
PropType
required?string
Typestring
minLength?(n: number) => string
Type(n: number) => string
maxLength?(n: number) => string
Type(n: number) => string
number?string
Typestring
wholeNumber?string
Typestring
minValue?(min: string) => string
Type(min: string) => string
maxValue?(max: string) => string
Type(max: string) => string
email?string
Typestring
url?string
Typestring

Slack doesn’t publish the exact wording of these client-side checks; they follow its client’s phrasing as closely as observed.

validateView

<Modal> runs this automatically on Submit, but it’s exported for anywhere you want the same check: a custom submit button, a test, or validating a view server-side before you even open it:

import { validateView } from "@nkootstra/block-kit";

const errors = validateView(view.blocks, state);
// { email: "Please complete this required field." }

if (Object.keys(errors).length === 0) {
  // safe to submit
}

validateView(blocks, state) returns errors keyed by block_id, the same shape as response_action: "errors" (see Modals), empty when every input block passes.

The errors prop

Errors an app returns from onSubmit (response_action: "errors") apply the way Slack’s client shows them: under the named block, clearing automatically once that field’s value changes. To seed a modal (or any surface) with errors up front instead, for a standalone <Modal> you’re previewing, or errors known before the user even touches the form, pass errors to <BlockKitProvider>:

<BlockKitProvider errors={{ email: "This address is already invited." }}>
  <Modal view={view} />
</BlockKitProvider>

<Modal>’s own client-side checks (required/length/format) and any onSubmit errors layer on top of the provider’s errors rather than replacing them.

Was this page helpful?