Validate Slot values

Slots can include rules to describe what content is valid.

Call validateEditorSlots when your application needs to check the content, for example before saving or submitting a form. Submission is an application action, not a built-in Slot event.

Validation reads a snapshot and returns findings; it does not resolve or rewrite Slot values. Built-in checks and registered async validators run only when you call the validation API. Editing invalidates previous results and cancels a pending editor validation run, but does not automatically start another run.

For validation while typing, register an editor update listener and debounce calls to validateEditorSlots. Handle cancelled runs, display only current results, and remove the listener and pending timer when your UI unmounts. Automatic scheduling belongs to the host; there is no built-in auto-validation option.

import { isSlotValidationCurrent, validateEditorSlots } from '@tiptap-pro/extension-slot'

try {
  const result = await validateEditorSlots({ editor })
  if (!isSlotValidationCurrent({ editor, result })) {
    showMessage('The document changed. Please submit again to validate the latest values.')
  } else if (result.valid) {
    save(editor.getJSON())
  } else {
    showIssues(result.issues)
  }
} catch (error) {
  if (error instanceof Error && error.name === 'AbortError') {
    showMessage('Validation was cancelled. Please submit again.')
  } else {
    throw error
  }
}

isSlotValidationCurrent checks that the result still matches the editor's current document and validation settings.

Define requiredness, length, content types and patterns in attrs.config:

const config = {
  required: true,
  constraints: {
    pattern: { source: '^ORD-\\d{4}$', message: 'Use ORD-0000' },
  },
}

editor.commands.insertSlot({ config })

For application-specific checks, persist a validator name and register its implementation:

Slot.configure({
  validators: {
    registeredPerson: async ({ slot, signal }) => {
      const found = await directory.find(slot.text, { signal })
      return found
        ? []
        : [
            {
              code: 'custom.person',
              message: 'Choose a registered person.',
            },
          ]
    },
  },
})

// When the slot is created, include the custom validator
editor.commands.insertSlot({
  config: {
    validators: [{ name: 'registeredPerson' }],
  },
})

Validation can be async, so an AbortSignal (the signal field) is passed to cancel the validation process if the document is edited during validation.

For checks that involve multiple fields, add a crossFieldRules entry to an owning Slot and register a crossFieldValidators function. Learn more in the API Reference.

If some validators are missing or failed, validateEditorSlots returns status: 'unavailable'.

See the API Reference for more info on validation.