---
title: "Allow filling only"
description: "Protect document content and assign individual slots with a ready-made policy."
canonical_url: "https://tiptap.dev/docs/composable-docs/slots/guides/fill-only"
---

# Allow filling only

Protect document content and assign individual slots with a ready-made policy.

To prevent users from editing content outside the slots, use the [`ContentProtection`](https://tiptap.dev/docs/composable-docs/content-protection/getting-started/overview.md) extension.

> **Interactive demo:** [SlotFilling](https://embed-pro.tiptap.dev/preview/Examples/SlotFilling)

The `ContentProtection` extension takes a [content protection policy](https://tiptap.dev/docs/composable-docs/content-protection/api-reference/policy.md). Use the [`createSlotFillingPolicy` utility](https://tiptap.dev/docs/composable-docs/slots/api-reference/utilities.md#createslotfillingpolicy) to allow editing inside slots while protecting their configuration and the surrounding document.

```ts
import { Slot, createSlotFillingPolicy } from '@tiptap-pro/extension-slot'
import { ContentProtection } from '@tiptap-pro/extension-content-protection'

const extensions = [
  StarterKit,
  Slot,
  ContentProtection.configure({
    policy: createSlotFillingPolicy(),
  }),
]
```

To allow users to edit selected slots, pass their IDs to the policy creator. This also allows editing content inside their nested slots. Use [higher-priority rules](https://tiptap.dev/docs/composable-docs/content-protection/guides/example-policies.md#protect-nested-content) to restrict nested content.

```ts
editor.commands.setContentProtectionPolicy({
  policy: createSlotFillingPolicy({
    editableSlotIds: ['summary', 'justification'],
  }),
})
```

## Assign slots by role

Roles belong to your application. To assign Slots by an ID prefix, read the current IDs, filter them in the host, and pass the exact IDs to `createSlotFillingPolicy`:

```ts
import { getSlots } from '@tiptap-pro/extension-slot'

function applyRole(role: 'Auditor' | 'Reviewer') {
  const prefix = role === 'Auditor' ? 'audit-' : 'review-'
  const editableSlotIds = getSlots({ document: editor.state.doc }).flatMap(({ id }) =>
    id && (id.startsWith(prefix) || id.startsWith('all-')) ? [id] : [],
  )
  editor.commands.setContentProtectionPolicy({
    policy: createSlotFillingPolicy({ editableSlotIds }),
  })
}
```

Call `applyRole` when the role or the set of Slot IDs changes. The policy contains exact IDs; it does not keep evaluating the prefix. An editable parent Slot also permits editing its nested content, so use higher-priority rules when a nested Slot needs a different assignment.

## Collaboration

Slots work with [Tiptap Collaboration](https://tiptap.dev/docs/editor/extensions/functionality/collaboration.md). Include `Slot` alongside `Collaboration` and `ContentProtection`, and disable StarterKit's local undo/redo with `StarterKit.configure({ undoRedo: false })`.

Slot content, IDs and configuration synchronize through the shared document. Each collaborator can use their own `editableSlotIds`: these restrict local edits without rejecting updates from other collaborators. Collaborative undo/redo also synchronizes without a local policy check. Slot snapshots and validation refresh when shared content changes; validation results and policies remain local.
