This is the full developer documentation for Portable Text
# Portable Text
> A JSON-based specification for structured block content
import '@/styles/globals.css'
import {
Card,
CardGrid,
LinkCard,
TabItem,
Tabs,
} from '@astrojs/starlight/components'
import PortableTextEditor from '../../components/editor/editor.astro'
Portable Text is an open specification for structured block content. Rich text, images, code blocks, and any custom type you define, stored as JSON and renderable anywhere.
[Get started →](/introduction/) · [Render PT content →](/rendering/) · [Build an editor →](/editor/getting-started/)
## Try the editor
Type, format, and see the Portable Text output in real time. This is the [Portable Text Editor](/editor/getting-started/): a fully customizable block content editor you can embed in any React application.
## Get started
## What does Portable Text look like?
The same content as an HTML string and as Portable Text:
```html
```
```json
[
{
"_type": "block",
"style": "normal",
"children": [
{ "_type": "span", "text": "Read the " },
{
"_type": "span",
"text": "documentation",
"marks": ["a1b2c3"]
},
{ "_type": "span", "text": " for " },
{
"_type": "span",
"text": "Portable Text",
"marks": ["strong"]
},
{ "_type": "span", "text": "." }
],
"markDefs": [
{
"_key": "a1b2c3",
"_type": "link",
"href": "/docs"
}
]
}
]
```
Because content is structured data, you can render it as HTML, React components, Markdown, PDFs, or any other format. [Learn more about Portable Text →](/introduction/)
## Learn more
# defineBehavior
> **defineBehavior**\<`TPayload`, `TBehaviorEventType`, `TGuardResponse`\>(`behavior`): [`Behavior`](/api/behaviors/type-aliases/behavior/)
Defined in: behavior.types.behavior.ts:56
## Type Parameters
### TPayload
`TPayload` *extends* `Record`\<`string`, `unknown`\>
### TBehaviorEventType
`TBehaviorEventType` *extends* `` `custom.${string}` `` \| `"*"` \| `"annotation.add"` \| `"annotation.remove"` \| `"block.set"` \| `"block.unset"` \| `"child.set"` \| `"child.unset"` \| `"decorator.add"` \| `"decorator.remove"` \| `"delete"` \| `"history.redo"` \| `"history.undo"` \| `"insert"` \| `"insert.block"` \| `"insert.child"` \| `"insert.text"` \| `"move.backward"` \| `"move.forward"` \| `"remove.text"` \| `"select"` \| `"set"` \| `"unset"` \| `"annotation.set"` \| `"annotation.toggle"` \| `"decorator.toggle"` \| `"delete.backward"` \| `"delete.block"` \| `"delete.child"` \| `"delete.forward"` \| `"delete.text"` \| `"deserialize"` \| `"deserialize.data"` \| `"deserialization.success"` \| `"deserialization.failure"` \| `"insert.blocks"` \| `"insert.break"` \| `"insert.inline object"` \| `"insert.soft break"` \| `"insert.span"` \| `"list item.add"` \| `"list item.remove"` \| `"list item.toggle"` \| `"move.block"` \| `"move.block down"` \| `"move.block up"` \| `"select.block"` \| `"select.previous block"` \| `"select.next block"` \| `"serialize"` \| `"serialize.data"` \| `"serialization.success"` \| `"serialization.failure"` \| `"split"` \| `"style.add"` \| `"style.remove"` \| `"style.toggle"` \| `"clipboard.copy"` \| `"clipboard.cut"` \| `"clipboard.paste"` \| `"drag.dragstart"` \| `"drag.drag"` \| `"drag.dragend"` \| `"drag.dragenter"` \| `"drag.dragover"` \| `"drag.dragleave"` \| `"drag.drop"` \| `"input.*"` \| `"keyboard.keydown"` \| `"keyboard.keyup"` \| `"mouse.click"` \| `"delete.*"` \| `"insert.*"` \| `"select.*"` \| `"set.*"` \| `"unset.*"` \| `"deserialize.*"` \| `"serialize.*"` \| `"split.*"` \| `"annotation.*"` \| `"remove.*"` \| `"block.*"` \| `"child.*"` \| `"decorator.*"` \| `"history.*"` \| `"move.*"` \| `"deserialization.*"` \| `"list item.*"` \| `"serialization.*"` \| `"style.*"` \| `"clipboard.*"` \| `"drag.*"` \| `"keyboard.*"` \| `"mouse.*"` = `` `custom.${string}` ``
### TGuardResponse
`TGuardResponse` = `true`
## Parameters
### behavior
[`Behavior`](/api/behaviors/type-aliases/behavior/)\<`TBehaviorEventType`, `TGuardResponse`, `ResolveBehaviorEvent`\<`TBehaviorEventType`, `TPayload`\>\>
## Returns
[`Behavior`](/api/behaviors/type-aliases/behavior/)
## Example
```tsx
const noLowerCaseA = defineBehavior({
on: 'insert.text',
guard: ({event, snapshot}) => event.text === 'a',
actions: [({event, snapshot}) => [{type: 'insert.text', text: 'A'}]],
})
```
# effect
> **effect**(`effect`): `object`
Defined in: behavior.types.action.ts:203
Performs a side effect.
Use `effect` for logging, analytics, async operations, or other side effects.
**Note:** Using `effect` alone (without `forward`) will stop event
propagation. To perform a side effect while allowing the default Behavior
to continue, combine `effect` with `forward`.
The effect callback receives a `send` function that can be used to send
events back to the editor asynchronously.
## Parameters
### effect
(`payload`) => `void`
## Returns
`object`
### effect()
> **effect**: (`payload`) => `void`
#### Parameters
##### payload
###### send
(`event`) => `void`
Send a Behavior Event back into the Editor.
**Example**
```ts
defineBehavior({
on: '...',
actions: [
() => [
effect(({send}) => {
doSomethingAsync()
.then(() => {
send({
type: '...',
})
})
})
],
],
})
```
#### Returns
`void`
### type
> **type**: `"effect"`
## Example
```ts
// Log events while preserving default Behavior
defineBehavior({
on: 'insert.text',
actions: [({event}) => [effect(() => console.log(event)), forward(event)]],
})
// Effect alone stops propagation (native event is cancelled)
defineBehavior({
on: 'keyboard.keydown',
actions: [() => [effect(() => console.log('key pressed'))]],
})
// Async effect that sends an event later
defineBehavior({
on: 'custom.save',
actions: [
() => [
effect(async ({send}) => {
await saveDocument()
send({type: 'custom.saved'})
}),
],
],
})
```
# execute
> **execute**(`event`): `object`
Defined in: behavior.types.action.ts:73
Directly executes an event, bypassing all Behavior matching.
Use `execute` when you want to perform an action without triggering any
Behaviors. The event is executed immediately as a direct operation.
## Parameters
### event
[`SyntheticBehaviorEvent`](/api/behaviors/type-aliases/syntheticbehaviorevent/)
## Returns
`object`
### event
> **event**: [`SyntheticBehaviorEvent`](/api/behaviors/type-aliases/syntheticbehaviorevent/)
### type
> **type**: `"execute"`
## Example
```ts
defineBehavior({
on: 'insert.text',
guard: ({event}) => event.text === 'a',
actions: [() => [execute({type: 'insert.text', text: 'b'})]],
})
```
# forward
> **forward**(`event`): `object`
Defined in: behavior.types.action.ts:116
Forwards an event to the next Behavior(s) in the current chain.
Use `forward` to pass an event to succeeding Behaviors without starting a
fresh lookup. This is useful for intercepting events, performing side
effects, and then letting the default handling continue.
**Key rule:** When forwarding to a different event type, only Behaviors that
were already in the remaining chain AND match the new type will run. This
means cross-type `forward` is mostly useful for falling through to default
Behaviors, not for triggering user-defined Behaviors of a different type.
To trigger all Behaviors for a different event type, use [raise](/api/behaviors/functions/raise/)
instead.
## Parameters
### event
[`SyntheticBehaviorEvent`](/api/behaviors/type-aliases/syntheticbehaviorevent/) | [`NativeBehaviorEvent`](/api/behaviors/type-aliases/nativebehaviorevent/) | [`CustomBehaviorEvent`](/api/behaviors/type-aliases/custombehaviorevent/)
## Returns
`object`
### event
> **event**: [`SyntheticBehaviorEvent`](/api/behaviors/type-aliases/syntheticbehaviorevent/) \| [`NativeBehaviorEvent`](/api/behaviors/type-aliases/nativebehaviorevent/) \| [`CustomBehaviorEvent`](/api/behaviors/type-aliases/custombehaviorevent/)
### type
> **type**: `"forward"`
## Example
```ts
// Intercept and forward same event type
defineBehavior({
on: 'insert.text',
actions: [({event}) => [effect(logEvent), forward(event)]],
})
// Forward to default handling of different event type
defineBehavior({
on: 'clipboard.paste',
actions: [
({event}) => {
const text = event.originEvent.dataTransfer?.getData('text/plain')
return text ? [forward({type: 'insert.text', text})] : []
},
],
})
```
# raise
> **raise**(`event`): `object`
Defined in: behavior.types.action.ts:155
Raises an event, triggering a fresh lookup of all Behaviors.
Use `raise` when you want to trigger an event "from scratch", including all
Behaviors that match the event type. This is the appropriate action when you
want to trigger Behaviors for a different event type.
If no Behavior matches the raised event, synthetic events will fall through
to their default operation.
## Parameters
### event
[`SyntheticBehaviorEvent`](/api/behaviors/type-aliases/syntheticbehaviorevent/) | [`CustomBehaviorEvent`](/api/behaviors/type-aliases/custombehaviorevent/)
## Returns
`object`
### event
> **event**: [`SyntheticBehaviorEvent`](/api/behaviors/type-aliases/syntheticbehaviorevent/) \| [`CustomBehaviorEvent`](/api/behaviors/type-aliases/custombehaviorevent/)
### type
> **type**: `"raise"`
## Example
```ts
// Raise a custom event that triggers other Behaviors
defineBehavior({
on: 'insert.text',
guard: ({event}) => event.text === 'a',
actions: [() => [raise({type: 'custom.specialInsert'})]],
})
// Raise a different event type (fresh lookup includes all Behaviors)
defineBehavior({
on: 'clipboard.paste',
actions: [
({event}) => {
const text = event.originEvent.dataTransfer?.getData('text/plain')
return text ? [raise({type: 'insert.text', text})] : []
},
],
})
```
# @portabletext/editor
## Type Aliases
- [Behavior](/api/behaviors/type-aliases/behavior/)
- [BehaviorAction](/api/behaviors/type-aliases/behavioraction/)
- [BehaviorActionSet](/api/behaviors/type-aliases/behavioractionset/)
- [BehaviorEvent](/api/behaviors/type-aliases/behaviorevent/)
- [BehaviorGuard](/api/behaviors/type-aliases/behaviorguard/)
- [CustomBehaviorEvent](/api/behaviors/type-aliases/custombehaviorevent/)
- [InsertPlacement](/api/behaviors/type-aliases/insertplacement/)
- [NativeBehaviorEvent](/api/behaviors/type-aliases/nativebehaviorevent/)
- [SyntheticBehaviorEvent](/api/behaviors/type-aliases/syntheticbehaviorevent/)
## Functions
- [defineBehavior](/api/behaviors/functions/definebehavior/)
- [effect](/api/behaviors/functions/effect/)
- [execute](/api/behaviors/functions/execute/)
- [forward](/api/behaviors/functions/forward/)
- [raise](/api/behaviors/functions/raise/)
# Behavior
> **Behavior**\<`TBehaviorEventType`, `TGuardResponse`, `TBehaviorEvent`\> = `object`
Defined in: behavior.types.behavior.ts:13
## Type Parameters
### TBehaviorEventType
`TBehaviorEventType` *extends* `"*"` \| `` `${BehaviorEventTypeNamespace}.*` `` \| [`BehaviorEvent`](/api/behaviors/type-aliases/behaviorevent/)\[`"type"`\] = `"*"` \| `` `${BehaviorEventTypeNamespace}.*` `` \| [`BehaviorEvent`](/api/behaviors/type-aliases/behaviorevent/)\[`"type"`\]
### TGuardResponse
`TGuardResponse` = `true`
### TBehaviorEvent
`TBehaviorEvent` *extends* `ResolveBehaviorEvent`\<`TBehaviorEventType`\> = `ResolveBehaviorEvent`\<`TBehaviorEventType`\>
## Properties
### actions
> **actions**: [`BehaviorActionSet`](/api/behaviors/type-aliases/behavioractionset/)\<`TBehaviorEvent`, `TGuardResponse`\>[]
Defined in: behavior.types.behavior.ts:39
Array of Behavior Action sets.
Each set represents a step in the history stack.
***
### guard?
> `optional` **guard**: [`BehaviorGuard`](/api/behaviors/type-aliases/behaviorguard/)\<`TBehaviorEvent`, `TGuardResponse`\>
Defined in: behavior.types.behavior.ts:34
Predicate function that determines if the Behavior should be executed.
Returning a non-nullable value from the guard will pass the value to the
actions and execute them.
***
### on
> **on**: `TBehaviorEventType`
Defined in: behavior.types.behavior.ts:28
Editor Event that triggers this Behavior.
# BehaviorAction
> **BehaviorAction** = \{ `event`: [`SyntheticBehaviorEvent`](/api/behaviors/type-aliases/syntheticbehaviorevent/); `type`: `"execute"`; \} \| \{ `event`: [`NativeBehaviorEvent`](/api/behaviors/type-aliases/nativebehaviorevent/) \| [`SyntheticBehaviorEvent`](/api/behaviors/type-aliases/syntheticbehaviorevent/) \| [`CustomBehaviorEvent`](/api/behaviors/type-aliases/custombehaviorevent/); `type`: `"forward"`; \} \| \{ `event`: [`SyntheticBehaviorEvent`](/api/behaviors/type-aliases/syntheticbehaviorevent/) \| [`CustomBehaviorEvent`](/api/behaviors/type-aliases/custombehaviorevent/); `type`: `"raise"`; \} \| \{ `effect`: (`payload`) => `void`; `type`: `"effect"`; \}
Defined in: behavior.types.action.ts:14
# BehaviorActionSet
> **BehaviorActionSet**\<`TBehaviorEvent`, `TGuardResponse`\> = (`payload`, `guardResponse`) => [`BehaviorAction`](/api/behaviors/type-aliases/behavioraction/)[]
Defined in: behavior.types.action.ts:212
## Type Parameters
### TBehaviorEvent
`TBehaviorEvent`
### TGuardResponse
`TGuardResponse`
## Parameters
### payload
#### dom
`EditorDom`
#### event
`TBehaviorEvent`
#### snapshot
`EditorSnapshot`
### guardResponse
`TGuardResponse`
## Returns
[`BehaviorAction`](/api/behaviors/type-aliases/behavioraction/)[]
# BehaviorEvent
> **BehaviorEvent** = [`SyntheticBehaviorEvent`](/api/behaviors/type-aliases/syntheticbehaviorevent/) \| [`NativeBehaviorEvent`](/api/behaviors/type-aliases/nativebehaviorevent/) \| [`CustomBehaviorEvent`](/api/behaviors/type-aliases/custombehaviorevent/)
Defined in: behavior.types.event.ts:20
# BehaviorGuard
> **BehaviorGuard**\<`TBehaviorEvent`, `TGuardResponse`\> = (`payload`) => `TGuardResponse` \| `false`
Defined in: behavior.types.guard.ts:7
## Type Parameters
### TBehaviorEvent
`TBehaviorEvent`
### TGuardResponse
`TGuardResponse`
## Parameters
### payload
#### dom
`EditorDom`
#### event
`TBehaviorEvent`
#### snapshot
`EditorSnapshot`
## Returns
`TGuardResponse` \| `false`
# CustomBehaviorEvent
> **CustomBehaviorEvent**\<`TPayload`, `TType`, `TInternalType`\> = `object` & `TPayload`
Defined in: behavior.types.event.ts:771
## Type Declaration
### type
> **type**: `TInternalType`
## Type Parameters
### TPayload
`TPayload` *extends* `Record`\<`string`, `unknown`\> = `Record`\<`string`, `unknown`\>
### TType
`TType` *extends* `string` = `string`
### TInternalType
`TInternalType` *extends* `CustomBehaviorEventType`\<`"custom"`, `TType`\> = `CustomBehaviorEventType`\<`"custom"`, `TType`\>
# InsertPlacement
> **InsertPlacement** = `"auto"` \| `"after"` \| `"before"`
Defined in: behavior.types.event.ts:331
# NativeBehaviorEvent
> **NativeBehaviorEvent** = `ClipboardBehaviorEvent` \| `DragBehaviorEvent` \| `InputBehaviorEvent` \| `KeyboardBehaviorEvent` \| `MouseBehaviorEvent`
Defined in: behavior.types.event.ts:636
# SyntheticBehaviorEvent
> **SyntheticBehaviorEvent** = \{ `annotation`: \{ `_key?`: `string`; `name`: `string`; `value`: \{\[`prop`: `string`\]: `unknown`; \}; \}; `at?`: `NonNullable`\<`EditorSelection`\>; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"annotation.add"`\>; \} \| \{ `annotation`: \{ `name`: `string`; \}; `at?`: `NonNullable`\<`EditorSelection`\>; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"annotation.remove"`\>; \} \| \{ `at`: `BlockPath`; `props`: `Record`\<`string`, `unknown`\>; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"block.set"`\>; \} \| \{ `at`: `BlockPath`; `props`: `string`[]; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"block.unset"`\>; \} \| \{ `at`: `ChildPath`; `props`: \{\[`prop`: `string`\]: `unknown`; \}; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"child.set"`\>; \} \| \{ `at`: `ChildPath`; `props`: `string`[]; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"child.unset"`\>; \} \| \{ `at?`: `NonNullable`\<`EditorSelection`\>; `decorator`: `string`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"decorator.add"`\>; \} \| \{ `at?`: `NonNullable`\<`EditorSelection`\>; `decorator`: `string`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"decorator.remove"`\>; \} \| \{ `at?`: `NonNullable`\<`EditorSelection`\>; `direction?`: `"backward"` \| `"forward"`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"delete"`\>; `unit?`: `"character"` \| `"word"` \| `"line"` \| `"block"` \| `"child"`; \} \| \{ `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"history.redo"`\>; \} \| \{ `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"history.undo"`\>; \} \| \{ `at`: `Path`; `position`: `"before"` \| `"after"`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"insert"`\>; `value`: `PortableTextTextBlock` \| `PortableTextObject` \| `PortableTextSpan`; \} \| \{ `at?`: `NonNullable`\<`EditorSelection`\>; `block`: `BlockWithOptionalKey`; `placement`: [`InsertPlacement`](/api/behaviors/type-aliases/insertplacement/); `select?`: `"start"` \| `"end"` \| `"none"`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"insert.block"`\>; \} \| \{ `child`: `ChildWithOptionalKey`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"insert.child"`\>; \} \| \{ `at?`: `Path`; `offset?`: `number`; `text`: `string`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"insert.text"`\>; \} \| \{ `distance`: `number`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"move.backward"`\>; \} \| \{ `distance`: `number`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"move.forward"`\>; \} \| \{ `at`: `Path`; `offset`: `number`; `text`: `string`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"remove.text"`\>; \} \| \{ `at`: `EditorSelection`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"select"`\>; \} \| \{ `at`: `Path`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"set"`\>; `value`: `unknown`; \} \| \{ `at`: `Path`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"unset"`\>; \} \| `AbstractBehaviorEvent`
Defined in: behavior.types.event.ts:102
## Type Declaration
\{ `annotation`: \{ `_key?`: `string`; `name`: `string`; `value`: \{\[`prop`: `string`\]: `unknown`; \}; \}; `at?`: `NonNullable`\<`EditorSelection`\>; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"annotation.add"`\>; \}
### annotation
> **annotation**: `object`
#### annotation.\_key?
> `optional` **\_key**: `string`
#### annotation.name
> **name**: `string`
#### annotation.value
> **value**: `object`
##### Index Signature
\[`prop`: `string`\]: `unknown`
### at?
> `optional` **at**: `NonNullable`\<`EditorSelection`\>
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"annotation.add"`\>
\{ `annotation`: \{ `name`: `string`; \}; `at?`: `NonNullable`\<`EditorSelection`\>; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"annotation.remove"`\>; \}
### annotation
> **annotation**: `object`
#### annotation.name
> **name**: `string`
### at?
> `optional` **at**: `NonNullable`\<`EditorSelection`\>
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"annotation.remove"`\>
\{ `at`: `BlockPath`; `props`: `Record`\<`string`, `unknown`\>; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"block.set"`\>; \}
### at
> **at**: `BlockPath`
### props
> **props**: `Record`\<`string`, `unknown`\>
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"block.set"`\>
\{ `at`: `BlockPath`; `props`: `string`[]; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"block.unset"`\>; \}
### at
> **at**: `BlockPath`
### props
> **props**: `string`[]
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"block.unset"`\>
\{ `at`: `ChildPath`; `props`: \{\[`prop`: `string`\]: `unknown`; \}; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"child.set"`\>; \}
### at
> **at**: `ChildPath`
### props
> **props**: `object`
#### Index Signature
\[`prop`: `string`\]: `unknown`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"child.set"`\>
\{ `at`: `ChildPath`; `props`: `string`[]; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"child.unset"`\>; \}
### at
> **at**: `ChildPath`
### props
> **props**: `string`[]
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"child.unset"`\>
\{ `at?`: `NonNullable`\<`EditorSelection`\>; `decorator`: `string`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"decorator.add"`\>; \}
### at?
> `optional` **at**: `NonNullable`\<`EditorSelection`\>
### decorator
> **decorator**: `string`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"decorator.add"`\>
\{ `at?`: `NonNullable`\<`EditorSelection`\>; `decorator`: `string`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"decorator.remove"`\>; \}
### at?
> `optional` **at**: `NonNullable`\<`EditorSelection`\>
### decorator
> **decorator**: `string`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"decorator.remove"`\>
\{ `at?`: `NonNullable`\<`EditorSelection`\>; `direction?`: `"backward"` \| `"forward"`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"delete"`\>; `unit?`: `"character"` \| `"word"` \| `"line"` \| `"block"` \| `"child"`; \}
### at?
> `optional` **at**: `NonNullable`\<`EditorSelection`\>
### direction?
> `optional` **direction**: `"backward"` \| `"forward"`
Defaults to forward deletion.
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"delete"`\>
### unit?
> `optional` **unit**: `"character"` \| `"word"` \| `"line"` \| `"block"` \| `"child"`
Defaults to character deletion.
\{ `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"history.redo"`\>; \}
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"history.redo"`\>
\{ `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"history.undo"`\>; \}
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"history.undo"`\>
\{ `at`: `Path`; `position`: `"before"` \| `"after"`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"insert"`\>; `value`: `PortableTextTextBlock` \| `PortableTextObject` \| `PortableTextSpan`; \}
### at
> **at**: `Path`
### position
> **position**: `"before"` \| `"after"`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"insert"`\>
Primitive: insert a node into an array.
The last segment of `at` resolves the insertion point:
- A keyed `{_key}` segment inserts relative to that sibling.
- A numeric index inserts relative to that slot.
`position` ('before' or 'after') is always meaningful: `before: [2]`
inserts at index 2, `after: [2]` inserts at index 3.
:::caution[Alpha]
This API should not be used in production and may be trimmed from a public release.
:::
#### Example
```ts
raise({
type: 'insert',
at: [{_key: 'list'}, 'items', {_key: 'item3'}],
value: newItem,
position: 'after',
})
```
### value
> **value**: `PortableTextTextBlock` \| `PortableTextObject` \| `PortableTextSpan`
\{ `at?`: `NonNullable`\<`EditorSelection`\>; `block`: `BlockWithOptionalKey`; `placement`: [`InsertPlacement`](/api/behaviors/type-aliases/insertplacement/); `select?`: `"start"` \| `"end"` \| `"none"`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"insert.block"`\>; \}
### at?
> `optional` **at**: `NonNullable`\<`EditorSelection`\>
### block
> **block**: `BlockWithOptionalKey`
### placement
> **placement**: [`InsertPlacement`](/api/behaviors/type-aliases/insertplacement/)
### select?
> `optional` **select**: `"start"` \| `"end"` \| `"none"`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"insert.block"`\>
\{ `child`: `ChildWithOptionalKey`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"insert.child"`\>; \}
### child
> **child**: `ChildWithOptionalKey`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"insert.child"`\>
\{ `at?`: `Path`; `offset?`: `number`; `text`: `string`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"insert.text"`\>; \}
### at?
> `optional` **at**: `Path`
### offset?
> `optional` **offset**: `number`
### text
> **text**: `string`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"insert.text"`\>
Inserts text into a span.
Without `at`/`offset`, text is inserted at the current caret position.
This is the form used by typing handlers.
With `at` and `offset`, text is inserted at the explicit position.
Recommended for plugin behaviors and collaborative-edit contexts.
:::caution[Alpha]
This API should not be used in production and may be trimmed from a public release.
:::
#### Example
```ts
// Caret form
raise({type: 'insert.text', text: 'x'})
// Primitive form (@alpha)
raise({
type: 'insert.text',
at: [{_key: 'b1'}, 'children', {_key: 's1'}],
offset: 5,
text: 'world',
})
```
\{ `distance`: `number`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"move.backward"`\>; \}
### distance
> **distance**: `number`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"move.backward"`\>
\{ `distance`: `number`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"move.forward"`\>; \}
### distance
> **distance**: `number`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"move.forward"`\>
\{ `at`: `Path`; `offset`: `number`; `text`: `string`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"remove.text"`\>; \}
### at
> **at**: `Path`
### offset
> **offset**: `number`
### text
> **text**: `string`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"remove.text"`\>
Primitive: remove text from a span at the given offset.
The `text` field carries the exact text being removed (matches the
apply-layer shape so the inverse can be computed without re-reading
the span).
Recommended for collaborative-edit contexts (concurrent edits compose
cleanly under operational transform).
:::caution[Alpha]
This API should not be used in production and may be trimmed from a public release.
:::
#### Example
```ts
raise({
type: 'remove.text',
at: [{_key: 'b1'}, 'children', {_key: 's1'}],
offset: 5,
text: 'world',
})
```
\{ `at`: `EditorSelection`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"select"`\>; \}
### at
> **at**: `EditorSelection`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"select"`\>
\{ `at`: `Path`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"set"`\>; `value`: `unknown`; \}
### at
> **at**: `Path`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"set"`\>
Primitive: set a property on a node, or replace a node wholesale.
The last segment of `at` is the property name (a string) for property
updates, OR a keyed/indexed segment for full-node replacement.
Note: `set` on span text (`{at: [...spanPath, 'text'], value: '...'}`)
is legal but not recommended in collaborative-edit contexts. Use
`insert.text` and `remove.text` for text edits that compose under
operational transform.
:::caution[Alpha]
This API should not be used in production and may be trimmed from a public release.
:::
#### Example
```ts
// Set a block's style
raise({type: 'set', at: [{_key: 'b1'}, 'style'], value: 'h1'})
// Replace a block wholesale
raise({type: 'set', at: [{_key: 'b1'}], value: newBlock})
```
### value
> **value**: `unknown`
\{ `at`: `Path`; `type`: `StrictExtract`\<`SyntheticBehaviorEventType`, `"unset"`\>; \}
### at
> **at**: `Path`
### type
> **type**: `StrictExtract`\<`SyntheticBehaviorEventType`, `"unset"`\>
Primitive: unset a property on an object, OR remove a node from an
array.
When the last segment of `at` is a string, the property is removed.
When the last segment is a keyed `{_key}` segment or a numeric index,
the node at that array position is removed.
:::caution[Alpha]
This API should not be used in production and may be trimmed from a public release.
:::
#### Example
```ts
// Remove a property
raise({type: 'unset', at: [{_key: 'b1'}, 'level']})
// Remove a node from an array
raise({type: 'unset', at: [{_key: 'list'}, 'items', {_key: 'item3'}]})
```
`AbstractBehaviorEvent`
# PortableTextEditor
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:33
:::caution[Deprecated]
Use `useEditor()` instead
```
import {useEditor} from '@portabletext/editor'
// Get the editor instance
const editor = useEditor()
// Send events to the editor
editor.send(...)
// Derive state from the editor
const state = useEditorSelector(editor, snapshot => ...)
```
:::
## Constructors
### Constructor
> **new PortableTextEditor**(`config`): `PortableTextEditor`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:43
#### Parameters
##### config
###### editable
`EditableAPI`
###### editorActor
`ActorRef`
#### Returns
`PortableTextEditor`
## Properties
### ~~schemaTypes~~
> **schemaTypes**: `Schema`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:37
A lookup table for all the relevant schema types for this portable text type.
## Methods
### ~~setEditable()~~
> **setEditable**(`editable`): `void`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:48
#### Parameters
##### editable
`EditableAPI`
#### Returns
`void`
***
### ~~activeAnnotations()~~
> `static` **activeAnnotations**(`editor`): [`PortableTextObject`](/api/editor/interfaces/portabletextobject/)[]
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:65
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const isActive = useEditorSelector(editor, selectors.getActiveAnnotations)
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
[`PortableTextObject`](/api/editor/interfaces/portabletextobject/)[]
***
### ~~addAnnotation()~~
> `static` **addAnnotation**\<`TSchemaType`\>(`editor`, `type`, `value?`): [`AddedAnnotationPaths`](/api/editor/type-aliases/addedannotationpaths/) \| `undefined`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:105
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'annotation.add',
annotation: {
name: '...',
value: {...},
}
})
```
:::
#### Type Parameters
##### TSchemaType
`TSchemaType` *extends* `object`
#### Parameters
##### editor
`PortableTextEditor`
##### type
`TSchemaType`
##### value?
#### Returns
[`AddedAnnotationPaths`](/api/editor/type-aliases/addedannotationpaths/) \| `undefined`
***
### ~~blur()~~
> `static` **blur**(`editor`): `void`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:123
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'blur',
})
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
`void`
***
### ~~delete()~~
> `static` **delete**(`editor`, `selection`, `options?`): `void`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:141
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'delete',
at: {...},
direction: '...',
unit: '...',
})
```
:::
#### Parameters
##### editor
`PortableTextEditor`
##### selection
[`EditorSelection`](/api/editor/type-aliases/editorselection/)
##### options?
[`EditableAPIDeleteOptions`](/api/editor/interfaces/editableapideleteoptions/)
#### Returns
`void`
***
### ~~findByPath()~~
> `static` **findByPath**(`editor`, `path`): \[[`PortableTextObject`](/api/editor/interfaces/portabletextobject/) \| [`PortableTextSpan`](/api/editor/interfaces/portabletextspan/) \| [`PortableTextTextBlock`](/api/editor/interfaces/portabletexttextblock/)\<[`PortableTextObject`](/api/editor/interfaces/portabletextobject/) \| [`PortableTextSpan`](/api/editor/interfaces/portabletextspan/)\> \| `undefined`, [`Path`](/api/editor/type-aliases/path/) \| `undefined`\]
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:154
#### Parameters
##### editor
`PortableTextEditor`
##### path
[`Path`](/api/editor/type-aliases/path/)
#### Returns
\[[`PortableTextObject`](/api/editor/interfaces/portabletextobject/) \| [`PortableTextSpan`](/api/editor/interfaces/portabletextspan/) \| [`PortableTextTextBlock`](/api/editor/interfaces/portabletexttextblock/)\<[`PortableTextObject`](/api/editor/interfaces/portabletextobject/) \| [`PortableTextSpan`](/api/editor/interfaces/portabletextspan/)\> \| `undefined`, [`Path`](/api/editor/type-aliases/path/) \| `undefined`\]
***
### ~~findDOMNode()~~
> `static` **findDOMNode**(`editor`, `element`): `Node` \| `undefined`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:147
#### Parameters
##### editor
`PortableTextEditor`
##### element
[`PortableTextObject`](/api/editor/interfaces/portabletextobject/) | [`PortableTextSpan`](/api/editor/interfaces/portabletextspan/) | [`PortableTextTextBlock`](/api/editor/interfaces/portabletexttextblock/)\<[`PortableTextObject`](/api/editor/interfaces/portabletextobject/) \| [`PortableTextSpan`](/api/editor/interfaces/portabletextspan/)\>
#### Returns
`Node` \| `undefined`
***
### ~~focus()~~
> `static` **focus**(`editor`): `void`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:169
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'focus',
})
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
`void`
***
### ~~focusBlock()~~
> `static` **focusBlock**(`editor`): [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/) \| `undefined`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:183
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const focusBlock = useEditorSelector(editor, selectors.getFocusBlock)
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
[`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/) \| `undefined`
***
### ~~focusChild()~~
> `static` **focusChild**(`editor`): [`PortableTextChild`](/api/editor/type-aliases/portabletextchild/) \| `undefined`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:197
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const focusChild = useEditorSelector(editor, selectors.getFocusChild)
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
[`PortableTextChild`](/api/editor/type-aliases/portabletextchild/) \| `undefined`
***
### ~~getFragment()~~
> `static` **getFragment**(`editor`): [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:485
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const selectedValue = useEditorSelector(editor, selectors.getSelectedValue)
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
[`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`
***
### ~~getSelection()~~
> `static` **getSelection**(`editor`): [`EditorSelection`](/api/editor/type-aliases/editorselection/)
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:213
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const selection = useEditorSelector(editor, selectors.getSelection)
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
[`EditorSelection`](/api/editor/type-aliases/editorselection/)
***
### ~~getValue()~~
> `static` **getValue**(`editor`): [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:227
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const value = useEditorSelector(editor, selectors.getValue)
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
[`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`
***
### ~~hasBlockStyle()~~
> `static` **hasBlockStyle**(`editor`, `blockStyle`): `boolean`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:241
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const isActive = useEditorSelector(editor, selectors.isActiveStyle(...))
```
:::
#### Parameters
##### editor
`PortableTextEditor`
##### blockStyle
`string`
#### Returns
`boolean`
***
### ~~hasListStyle()~~
> `static` **hasListStyle**(`editor`, `listStyle`): `boolean`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:255
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const isActive = useEditorSelector(editor, selectors.isActiveListItem(...))
```
:::
#### Parameters
##### editor
`PortableTextEditor`
##### listStyle
`string`
#### Returns
`boolean`
***
### ~~insertBlock()~~
> `static` **insertBlock**\<`TSchemaType`\>(`editor`, `type`, `value?`): [`Path`](/api/editor/type-aliases/path/) \| `undefined`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:343
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'insert.block object',
blockObject: {
name: '...',
value: {...},
},
placement: 'auto' | 'after' | 'before',
})
```
:::
#### Type Parameters
##### TSchemaType
`TSchemaType` *extends* `object`
#### Parameters
##### editor
`PortableTextEditor`
##### type
`TSchemaType`
##### value?
#### Returns
[`Path`](/api/editor/type-aliases/path/) \| `undefined`
***
### ~~insertBreak()~~
> `static` **insertBreak**(`editor`): `void`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:362
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'insert.break',
})
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
`void`
***
### ~~insertChild()~~
> `static` **insertChild**\<`TSchemaType`\>(`editor`, `type`, `value?`): [`Path`](/api/editor/type-aliases/path/) \| `undefined`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:319
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'insert.span',
text: '...',
annotations: [{name: '...', value: {...}}],
decorators: ['...'],
})
editor.send({
type: 'insert.inline object',
inlineObject: {
name: '...',
value: {...},
},
})
```
:::
#### Type Parameters
##### TSchemaType
`TSchemaType` *extends* `object`
#### Parameters
##### editor
`PortableTextEditor`
##### type
`TSchemaType`
##### value?
#### Returns
[`Path`](/api/editor/type-aliases/path/) \| `undefined`
***
### ~~isAnnotationActive()~~
> `static` **isAnnotationActive**(`editor`, `annotationType`): `boolean`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:81
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const isActive = useEditorSelector(editor, selectors.isActiveAnnotation(...))
```
:::
#### Parameters
##### editor
`PortableTextEditor`
##### annotationType
`string`
#### Returns
`boolean`
***
### ~~isCollapsedSelection()~~
> `static` **isCollapsedSelection**(`editor`): `boolean`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:269
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const isSelectionCollapsed = useEditorSelector(editor, selectors.isSelectionCollapsed)
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
`boolean`
***
### ~~isExpandedSelection()~~
> `static` **isExpandedSelection**(`editor`): `boolean`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:282
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const isSelectionExpanded = useEditorSelector(editor, selectors.isSelectionExpanded)
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
`boolean`
***
### ~~isMarkActive()~~
> `static` **isMarkActive**(`editor`, `mark`): `boolean`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:295
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const isActive = useEditorSelector(editor, selectors.isActiveDecorator(...))
```
:::
#### Parameters
##### editor
`PortableTextEditor`
##### mark
`string`
#### Returns
`boolean`
***
### ~~isObjectPath()~~
> `static` **isObjectPath**(`_editor`, `path`): `boolean`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:373
#### Parameters
##### \_editor
`PortableTextEditor`
##### path
[`Path`](/api/editor/type-aliases/path/)
#### Returns
`boolean`
***
### ~~isSelectionsOverlapping()~~
> `static` **isSelectionsOverlapping**(`editor`, `selectionA`, `selectionB`): `boolean`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:531
:::caution[Deprecated]
Use built-in selectors or write your own: https://www.portabletext.org/reference/selectors/
```
import * as selectors from '@portabletext/editor/selectors'
const editor = useEditor()
const isOverlapping = useEditorSelector(editor, selectors.isOverlappingSelection(selectionB))
```
:::
#### Parameters
##### editor
`PortableTextEditor`
##### selectionA
[`EditorSelection`](/api/editor/type-aliases/editorselection/)
##### selectionB
[`EditorSelection`](/api/editor/type-aliases/editorselection/)
#### Returns
`boolean`
***
### ~~isVoid()~~
> `static` **isVoid**(`editor`, `element`): `boolean`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:366
#### Parameters
##### editor
`PortableTextEditor`
##### element
[`PortableTextObject`](/api/editor/interfaces/portabletextobject/) | [`PortableTextSpan`](/api/editor/interfaces/portabletextspan/) | [`PortableTextTextBlock`](/api/editor/interfaces/portabletexttextblock/)\<[`PortableTextObject`](/api/editor/interfaces/portabletextobject/) \| [`PortableTextSpan`](/api/editor/interfaces/portabletextspan/)\>
#### Returns
`boolean`
***
### ~~marks()~~
> `static` **marks**(`editor`): `string`[]
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:382
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
`string`[]
***
### ~~redo()~~
> `static` **redo**(`editor`): `void`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:517
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'history.redo',
})
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
`void`
***
### ~~removeAnnotation()~~
> `static` **removeAnnotation**\<`TSchemaType`\>(`editor`, `type`): `void`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:419
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'annotation.remove',
annotation: {
name: '...',
},
})
```
:::
#### Type Parameters
##### TSchemaType
`TSchemaType` *extends* `object`
#### Parameters
##### editor
`PortableTextEditor`
##### type
`TSchemaType`
#### Returns
`void`
***
### ~~select()~~
> `static` **select**(`editor`, `selection`): `void`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:398
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'select',
selection: {...},
})
```
:::
#### Parameters
##### editor
`PortableTextEditor`
##### selection
[`EditorSelection`](/api/editor/type-aliases/editorselection/)
#### Returns
`void`
***
### ~~toggleBlockStyle()~~
> `static` **toggleBlockStyle**(`editor`, `blockStyle`): `void`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:436
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'style.toggle',
style: '...',
})
```
:::
#### Parameters
##### editor
`PortableTextEditor`
##### blockStyle
`string`
#### Returns
`void`
***
### ~~toggleList()~~
> `static` **toggleList**(`editor`, `listStyle`): `void`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:455
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'list item.toggle',
listItem: '...',
})
```
:::
#### Parameters
##### editor
`PortableTextEditor`
##### listStyle
`string`
#### Returns
`void`
***
### ~~toggleMark()~~
> `static` **toggleMark**(`editor`, `mark`): `void`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:471
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'decorator.toggle',
decorator: '...',
})
```
:::
#### Parameters
##### editor
`PortableTextEditor`
##### mark
`string`
#### Returns
`void`
***
### ~~undo()~~
> `static` **undo**(`editor`): `void`
Defined in: packages/editor/src/editor/PortableTextEditor.tsx:502
:::caution[Deprecated]
Use `editor.send(...)` instead
```
const editor = useEditor()
editor.send({
type: 'history.undo',
})
```
:::
#### Parameters
##### editor
`PortableTextEditor`
#### Returns
`void`
# defineAnnotation
> **defineAnnotation**(`config`): [`Annotation`](/api/editor/type-aliases/annotation/)
Defined in: packages/editor/src/renderers/renderer.types.ts:556
Define an annotation renderer for a `_type` declared in the
schema's `annotations` array, or `'*'` to match every annotation
type. The returned registration is mounted via the ``
component.
Annotation `_type`s live in a different namespace than node
`_type`s, so `type` has no forbidden values here (unlike
`defineInlineObject`/`defineBlockObject`).
## Parameters
### config
#### render?
[`AnnotationRender`](/api/editor/type-aliases/annotationrender/)
#### type
`string`
## Returns
[`Annotation`](/api/editor/type-aliases/annotation/)
## Example
```ts
defineAnnotation({
type: 'link',
render: ({annotation, children}) => (
{children}
),
})
```
# defineBlockObject
> **defineBlockObject**\<`TType`\>(`config`): [`BlockObject`](/api/editor/type-aliases/blockobject/)
Defined in: packages/editor/src/renderers/renderer.types.ts:587
Define a non-editable block-level object renderer for a `_type`
declared in the schema's `blockObjects` array.
The render must always render `children` somewhere inside the outer
element. `children` carries an engine-emitted void spacer the browser
uses to anchor the caret next to the element. Dropping `children`
makes the caret unable to land on the element.
## Type Parameters
### TType
`TType` *extends* `string`
## Parameters
### config
#### render?
[`BlockObjectRender`](/api/editor/type-aliases/blockobjectrender/)
#### type
`TType` *extends* `"block"` ? `"Error: defineBlockObject({type: 'block'}) is forbidden -- 'block' is always a text block, use defineTextBlock"` : `TType` *extends* `"span"` ? `"Error: defineBlockObject({type: 'span'}) is forbidden -- 'span' is always a span, use defineSpan"` : `TType`
## Returns
[`BlockObject`](/api/editor/type-aliases/blockobject/)
## Example
```ts
defineBlockObject({
type: 'image',
render: ({attributes, children, node}) => (
{children}
),
})
```
# defineContainer
> **defineContainer**\<`TType`\>(`config`): [`Container`](/api/editor/type-aliases/container/)
Defined in: packages/editor/src/renderers/renderer.types.ts:452
Define a container renderer. The returned registration is mounted via
the `` component at the top level, or nested inside
another container's `of` array as a positional override.
`type` cannot be `'span'` (use [defineSpan](/api/editor/functions/definespan/)) nor `'block'` (use
[defineTextBlock](/api/editor/functions/definetextblock/)). The text block is not a container.
The `node` argument of `render` narrows to a portable text object.
## Type Parameters
### TType
`TType` *extends* `string`
## Parameters
### config
#### arrayField
`string`
#### of?
readonly ([`Container`](/api/editor/type-aliases/container/) \| [`TextBlock`](/api/editor/type-aliases/textblock/) \| [`BlockObject`](/api/editor/type-aliases/blockobject/))[]
#### render?
(`props`) => `ReactElement`
#### type
`TType` *extends* `"span"` ? `"Error: defineContainer({type: 'span'}) is forbidden -- 'span' is always a span, use defineSpan"` : `TType` *extends* `"block"` ? `"Error: defineContainer({type: 'block'}) is forbidden -- 'block' is always a text block, use defineTextBlock"` : `TType` *extends* `"*"` ? `"Error: defineContainer({type: '*'}) is forbidden -- containers cannot be registered by wildcard"` : `TType`
## Returns
[`Container`](/api/editor/type-aliases/container/)
## Example
```ts
defineContainer({
type: 'table',
arrayField: 'rows',
render: ({children}) => (
),
}),
],
})
```
# defineDecorator
> **defineDecorator**(`config`): [`Decorator`](/api/editor/type-aliases/decorator/)
Defined in: packages/editor/src/renderers/renderer.types.ts:527
Define a decorator renderer for a decorator name declared in the
schema's `decorators` array, or `'*'` to match every decorator.
The returned registration is mounted via the ``
component.
Decorator names live in a different namespace than node
`_type`s, so `type` has no forbidden values here (unlike
`defineSpan`/`defineTextBlock`).
## Parameters
### config
#### render?
[`DecoratorRender`](/api/editor/type-aliases/decoratorrender/)
#### type
`string`
## Returns
[`Decorator`](/api/editor/type-aliases/decorator/)
## Example
```ts
defineDecorator({
type: 'strong',
render: ({children}) => {children},
})
```
# defineInlineObject
> **defineInlineObject**\<`TType`\>(`config`): [`InlineObject`](/api/editor/type-aliases/inlineobject/)
Defined in: packages/editor/src/renderers/renderer.types.ts:622
Define a non-editable inline object renderer for a `_type` declared
in the schema's `inlineObjects` array.
The render must always render `children` somewhere inside the outer
element. `children` carries an engine-emitted void spacer the browser
uses to anchor the caret next to the element. Dropping `children`
makes the caret unable to land on the element.
## Type Parameters
### TType
`TType` *extends* `string`
## Parameters
### config
#### render?
[`InlineObjectRender`](/api/editor/type-aliases/inlineobjectrender/)
#### type
`TType` *extends* `"block"` ? `"Error: defineInlineObject({type: 'block'}) is forbidden -- 'block' is always a text block, use defineTextBlock"` : `TType` *extends* `"span"` ? `"Error: defineInlineObject({type: 'span'}) is forbidden -- 'span' is always a span, use defineSpan"` : `TType`
## Returns
[`InlineObject`](/api/editor/type-aliases/inlineobject/)
## Example
```ts
defineInlineObject({
type: 'mention',
render: ({attributes, children, node}) => (
{children}
@{(node as {username?: string}).username}
),
})
```
# defineSchema
> **defineSchema**\<`TSchemaDefinition`\>(`definition`): `TSchemaDefinition`
Defined in: packages/schema/dist/index.d.ts:189
A helper wrapper that adds editor support, such as autocomplete and type checking, for a schema definition.
## Type Parameters
### TSchemaDefinition
`TSchemaDefinition` *extends* [`SchemaDefinition`](/api/editor/type-aliases/schemadefinition/)
## Parameters
### definition
`TSchemaDefinition`
## Returns
`TSchemaDefinition`
## Example
```ts
import { defineSchema } from '@portabletext/editor'
const schemaDefinition = defineSchema({
decorators: [{name: 'strong'}, {name: 'em'}, {name: 'underline'}],
annotations: [{name: 'link'}],
styles: [
{name: 'normal'},
{name: 'h1'},
{name: 'h2'},
{name: 'h3'},
{name: 'blockquote'},
],
lists: [],
inlineObjects: [],
blockObjects: [],
}
```
# defineSpan
> **defineSpan**\<`TType`\>(`config`): [`Span`](/api/editor/type-aliases/span/)
Defined in: packages/editor/src/renderers/renderer.types.ts:498
Define a span renderer. The returned registration is mounted via the
`` component at the top level, or nested inside a
container's `of` array as a positional override.
`type` is required even though there is only one top-level span type
(`'span'`) today. Keeping `type` required leaves the door open for
positional overrides of span-like inlines (e.g. a `code-span` inside
a `code-block` container).
## Type Parameters
### TType
`TType` *extends* `string`
## Parameters
### config
#### render?
[`SpanRender`](/api/editor/type-aliases/spanrender/)
#### type
`TType` *extends* `"block"` ? `"Error: defineSpan({type: 'block'}) is forbidden -- 'block' is always a text block, use defineTextBlock"` : `TType`
## Returns
[`Span`](/api/editor/type-aliases/span/)
## Example
```ts
defineSpan({
type: 'span',
render: ({attributes, children}) => (
{children}
),
})
```
# defineTextBlock
> **defineTextBlock**\<`TType`\>(`config`): [`TextBlock`](/api/editor/type-aliases/textblock/)
Defined in: packages/editor/src/renderers/renderer.types.ts:655
Define a text block renderer. The returned registration is mounted
via the `` component, or nested inside a container's
`of` array as a positional override.
`type` is required even though the top-level text block type is
always `'block'`. Keeping `type` required leaves the door open for
positional overrides of text-block-like elements (e.g. a `code-line`
inside a `code-block` container).
## Type Parameters
### TType
`TType` *extends* `string`
## Parameters
### config
#### of?
readonly ([`Span`](/api/editor/type-aliases/span/) \| [`InlineObject`](/api/editor/type-aliases/inlineobject/) \| [`Decorator`](/api/editor/type-aliases/decorator/) \| [`Annotation`](/api/editor/type-aliases/annotation/))[]
#### render?
[`TextBlockRender`](/api/editor/type-aliases/textblockrender/)
#### type
`TType` *extends* `"span"` ? `"Error: defineTextBlock({type: 'span'}) is forbidden -- 'span' is always a span, use defineSpan"` : `TType`
## Returns
[`TextBlock`](/api/editor/type-aliases/textblock/)
## Example
```ts
defineTextBlock({
type: 'block',
render: ({attributes, children}) => (
{children}
),
})
```
# EditorProvider
> **EditorProvider**(`props`): `Element`
Defined in: packages/editor/src/editor/editor-provider.tsx:39
The EditorProvider component is used to set up the editor context and configure the Portable Text Editor.
## Parameters
### props
[`EditorProviderProps`](/api/editor/type-aliases/editorproviderprops/)
## Returns
`Element`
## Example
```tsx
import {EditorProvider} from '@portabletext/editor'
function App() {
return (
...
)
}
```
# keyGenerator
> **keyGenerator**(): `string`
Defined in: packages/editor/src/utils/key-generator.ts:4
## Returns
`string`
# useEditor
> **useEditor**(): [`Editor`](/api/editor/type-aliases/editor/)
Defined in: packages/editor/src/editor/use-editor.ts:19
Get the current editor context from the `EditorProvider`.
Must be used inside the `EditorProvider` component.
## Returns
[`Editor`](/api/editor/type-aliases/editor/)
The current editor object.
## Example
```tsx
import { useEditor } from '@portabletext/editor'
function MyComponent() {
const editor = useEditor()
}
```
# useEditorSelector
> **useEditorSelector**\<`TSelected`\>(`editor`, `selector`, `compare`): `TSelected`
Defined in: packages/editor/src/editor/editor-selector.ts:39
Hook to select a value from the editor state.
## Type Parameters
### TSelected
`TSelected`
## Parameters
### editor
[`Editor`](/api/editor/type-aliases/editor/)
### selector
[`EditorSelector`](/api/editor/type-aliases/editorselector/)\<`TSelected`\>
### compare
(`a`, `b`) => `boolean`
## Returns
`TSelected`
## Examples
Pass a selector as the second argument
```tsx
import { useEditorSelector } from '@portabletext/editor'
function MyComponent(editor) {
const value = useEditorSelector(editor, selector)
}
```
Pass an inline selector as the second argument.
In this case, use the editor context to obtain the schema.
```tsx
import { useEditorSelector } from '@portabletext/editor'
function MyComponent(editor) {
const schema = useEditorSelector(editor, (snapshot) => snapshot.context.schema)
}
```
# usePortableTextEditor
> **usePortableTextEditor**(): [`PortableTextEditor`](/api/editor/classes/portabletexteditor/)
Defined in: packages/editor/src/editor/usePortableTextEditor.ts:15
:::caution[Deprecated]
Use `useEditor` to get the current editor instance.
Get the current editor object from the React context.
:::
## Returns
[`PortableTextEditor`](/api/editor/classes/portabletexteditor/)
# usePortableTextEditorSelection
> **usePortableTextEditorSelection**(): [`EditorSelection`](/api/editor/type-aliases/editorselection/)
Defined in: packages/editor/src/editor/usePortableTextEditorSelection.tsx:11
:::caution[Deprecated]
Use `useEditorSelector` to get the current editor selection.
Get the current editor selection from the React context.
:::
## Returns
[`EditorSelection`](/api/editor/type-aliases/editorselection/)
# EditableAPIDeleteOptions
Defined in: packages/editor/src/types/editor.ts:20
:::caution[Deprecated]
`EditableAPIDeleteOptions` is deprecated together with the
`PortableTextEditor.delete` static. Send a `delete` behavior event (with
an optional `unit`) or a `delete.block` event via `editor.send` instead.
:::
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### ~~mode?~~
> `optional` **mode**: `"blocks"` \| `"children"` \| `"selected"`
Defined in: packages/editor/src/types/editor.ts:21
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# PasteData
Defined in: packages/editor/src/types/editor.ts:145
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### event
> **event**: `ClipboardEvent`
Defined in: packages/editor/src/types/editor.ts:146
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
***
### path
> **path**: [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/types/editor.ts:147
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
***
### schemaTypes
> **schemaTypes**: `Schema`
Defined in: packages/editor/src/types/editor.ts:148
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
***
### value
> **value**: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`
Defined in: packages/editor/src/types/editor.ts:149
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# PortableTextObject
Defined in: packages/schema/dist/index.d.ts:294
## Indexable
\[`other`: `string`\]: `unknown`
## Properties
### \_key
> **\_key**: `string`
Defined in: packages/schema/dist/index.d.ts:296
***
### \_type
> **\_type**: `string`
Defined in: packages/schema/dist/index.d.ts:295
# PortableTextSpan
Defined in: packages/schema/dist/index.d.ts:279
## Properties
### \_key
> **\_key**: `string`
Defined in: packages/schema/dist/index.d.ts:280
***
### \_type
> **\_type**: `"span"`
Defined in: packages/schema/dist/index.d.ts:281
***
### marks?
> `optional` **marks**: `string`[]
Defined in: packages/schema/dist/index.d.ts:283
***
### text
> **text**: `string`
Defined in: packages/schema/dist/index.d.ts:282
# PortableTextTextBlock
Defined in: packages/schema/dist/index.d.ts:261
## Type Parameters
### TChild
`TChild` = [`PortableTextSpan`](/api/editor/interfaces/portabletextspan/) \| [`PortableTextObject`](/api/editor/interfaces/portabletextobject/)
## Properties
### \_key
> **\_key**: `string`
Defined in: packages/schema/dist/index.d.ts:263
***
### \_type
> **\_type**: `string`
Defined in: packages/schema/dist/index.d.ts:262
***
### children
> **children**: `TChild`[]
Defined in: packages/schema/dist/index.d.ts:264
***
### level?
> `optional` **level**: `number`
Defined in: packages/schema/dist/index.d.ts:268
***
### listItem?
> `optional` **listItem**: `string`
Defined in: packages/schema/dist/index.d.ts:266
***
### markDefs?
> `optional` **markDefs**: [`PortableTextObject`](/api/editor/interfaces/portabletextobject/)[]
Defined in: packages/schema/dist/index.d.ts:265
***
### style?
> `optional` **style**: `string`
Defined in: packages/schema/dist/index.d.ts:267
# RangeDecoration
Defined in: packages/editor/src/types/editor.ts:192
A UI affordance that wraps a selection range in the editor with a custom
component, for example to highlight search results, mark validation
errors on specific words, or draw user presence.
## Properties
### component()
> **component**: (`props`) => `ReactElement`\<`any`\>
Defined in: packages/editor/src/types/editor.ts:212
The component that renders the range decoration. It receives the
decorated text as its children.
The component can render more than once for one decoration: the range
is split into segments at formatting boundaries and where it overlaps
other decorations, and each segment gets its own wrapper. Where
decorations overlap, their components nest, first in array order
outermost.
#### Parameters
##### props
###### children?
`ReactNode`
#### Returns
`ReactElement`\<`any`\>
#### Example
```tsx
(rangeComponentProps: PropsWithChildren) => (
{rangeComponentProps.children}
)
```
***
### onMoved()?
> `optional` **onMoved**: (`details`) => `void`
Defined in: packages/editor/src/types/editor.ts:222
Called when edits move the decorated range. The details carry the new
selection (`null` when the range is lost) and whether the edit was
`local` or `remote`.
#### Parameters
##### details
[`RangeDecorationOnMovedDetails`](/api/editor/interfaces/rangedecorationonmoveddetails/)
#### Returns
`void`
***
### payload?
> `optional` **payload**: `Record`\<`string`, `unknown`\>
Defined in: packages/editor/src/types/editor.ts:226
A custom payload that can be set on the range decoration.
***
### selection
> **selection**: [`EditorSelection`](/api/editor/type-aliases/editorselection/)
Defined in: packages/editor/src/types/editor.ts:216
The editor content selection range to decorate.
# RangeDecorationOnMovedDetails
Defined in: packages/editor/src/types/editor.ts:182
Details passed to a `RangeDecoration`'s `onMoved` callback.
## Properties
### newSelection
> **newSelection**: [`EditorSelection`](/api/editor/type-aliases/editorselection/)
Defined in: packages/editor/src/types/editor.ts:184
***
### origin
> **origin**: `"local"` \| `"remote"`
Defined in: packages/editor/src/types/editor.ts:185
***
### rangeDecoration
> **rangeDecoration**: [`RangeDecoration`](/api/editor/interfaces/rangedecoration/)
Defined in: packages/editor/src/types/editor.ts:183
# @portabletext/editor
## Classes
- [~~PortableTextEditor~~](/api/editor/classes/portabletexteditor/)
## Interfaces
- [~~EditableAPIDeleteOptions~~](/api/editor/interfaces/editableapideleteoptions/)
- [PasteData](/api/editor/interfaces/pastedata/)
- [PortableTextObject](/api/editor/interfaces/portabletextobject/)
- [PortableTextSpan](/api/editor/interfaces/portabletextspan/)
- [PortableTextTextBlock](/api/editor/interfaces/portabletexttextblock/)
- [RangeDecoration](/api/editor/interfaces/rangedecoration/)
- [RangeDecorationOnMovedDetails](/api/editor/interfaces/rangedecorationonmoveddetails/)
## Type Aliases
- [AddedAnnotationPaths](/api/editor/type-aliases/addedannotationpaths/)
- [Annotation](/api/editor/type-aliases/annotation/)
- [AnnotationDefinition](/api/editor/type-aliases/annotationdefinition/)
- [AnnotationPath](/api/editor/type-aliases/annotationpath/)
- [AnnotationRender](/api/editor/type-aliases/annotationrender/)
- [AnnotationRenderProps](/api/editor/type-aliases/annotationrenderprops/)
- [AnnotationSchemaType](/api/editor/type-aliases/annotationschematype/)
- [BaseDefinition](/api/editor/type-aliases/basedefinition/)
- [BlockObject](/api/editor/type-aliases/blockobject/)
- [BlockObjectDefinition](/api/editor/type-aliases/blockobjectdefinition/)
- [BlockObjectRender](/api/editor/type-aliases/blockobjectrender/)
- [BlockObjectRenderProps](/api/editor/type-aliases/blockobjectrenderprops/)
- [BlockObjectSchemaType](/api/editor/type-aliases/blockobjectschematype/)
- [BlockOffset](/api/editor/type-aliases/blockoffset/)
- [BlockPath](/api/editor/type-aliases/blockpath/)
- [ChildPath](/api/editor/type-aliases/childpath/)
- [Container](/api/editor/type-aliases/container/)
- [ContainerRender](/api/editor/type-aliases/containerrender/)
- [ContainerRenderProps](/api/editor/type-aliases/containerrenderprops/)
- [Containers](/api/editor/type-aliases/containers/)
- [Decorator](/api/editor/type-aliases/decorator/)
- [DecoratorDefinition](/api/editor/type-aliases/decoratordefinition/)
- [DecoratorRender](/api/editor/type-aliases/decoratorrender/)
- [DecoratorRenderProps](/api/editor/type-aliases/decoratorrenderprops/)
- [DecoratorSchemaType](/api/editor/type-aliases/decoratorschematype/)
- [Editor](/api/editor/type-aliases/editor/)
- [EditorConfig](/api/editor/type-aliases/editorconfig/)
- [EditorContext](/api/editor/type-aliases/editorcontext/)
- [EditorEmittedEvent](/api/editor/type-aliases/editoremittedevent/)
- [EditorEvent](/api/editor/type-aliases/editorevent/)
- [EditorProviderProps](/api/editor/type-aliases/editorproviderprops/)
- [EditorSchema](/api/editor/type-aliases/editorschema/)
- [EditorSelection](/api/editor/type-aliases/editorselection/)
- [EditorSelectionPoint](/api/editor/type-aliases/editorselectionpoint/)
- [EditorSelector](/api/editor/type-aliases/editorselector/)
- [EditorSnapshot](/api/editor/type-aliases/editorsnapshot/)
- [FieldDefinition](/api/editor/type-aliases/fielddefinition/)
- [HotkeyOptions](/api/editor/type-aliases/hotkeyoptions/)
- [InlineObject](/api/editor/type-aliases/inlineobject/)
- [InlineObjectDefinition](/api/editor/type-aliases/inlineobjectdefinition/)
- [InlineObjectRender](/api/editor/type-aliases/inlineobjectrender/)
- [InlineObjectRenderProps](/api/editor/type-aliases/inlineobjectrenderprops/)
- [InlineObjectSchemaType](/api/editor/type-aliases/inlineobjectschematype/)
- [InvalidValueResolution](/api/editor/type-aliases/invalidvalueresolution/)
- [ListDefinition](/api/editor/type-aliases/listdefinition/)
- [ListSchemaType](/api/editor/type-aliases/listschematype/)
- [MutationEvent](/api/editor/type-aliases/mutationevent/)
- [OfDefinition](/api/editor/type-aliases/ofdefinition/)
- [OnCopyFn](/api/editor/type-aliases/oncopyfn/)
- [OnPasteFn](/api/editor/type-aliases/onpastefn/)
- [OnPasteResult](/api/editor/type-aliases/onpasteresult/)
- [OnPasteResultOrPromise](/api/editor/type-aliases/onpasteresultorpromise/)
- [Operation](/api/editor/type-aliases/operation/)
- [Patch](/api/editor/type-aliases/patch/)
- [PatchesEvent](/api/editor/type-aliases/patchesevent/)
- [Path](/api/editor/type-aliases/path/)
- [PortableTextBlock](/api/editor/type-aliases/portabletextblock/)
- [PortableTextChild](/api/editor/type-aliases/portabletextchild/)
- [PortableTextEditableProps](/api/editor/type-aliases/portabletexteditableprops/)
- [RegisteredBlockObject](/api/editor/type-aliases/registeredblockobject/)
- [RegisteredContainer](/api/editor/type-aliases/registeredcontainer/)
- [RegisteredInlineObject](/api/editor/type-aliases/registeredinlineobject/)
- [RegisteredPositional](/api/editor/type-aliases/registeredpositional/)
- [RegisteredSpan](/api/editor/type-aliases/registeredspan/)
- [RegistrableNode](/api/editor/type-aliases/registrablenode/)
- [RenderEditableFunction](/api/editor/type-aliases/rendereditablefunction/)
- [RenderPlaceholderFunction](/api/editor/type-aliases/renderplaceholderfunction/)
- [SchemaDefinition](/api/editor/type-aliases/schemadefinition/)
- [ScrollSelectionIntoViewFunction](/api/editor/type-aliases/scrollselectionintoviewfunction/)
- [Span](/api/editor/type-aliases/span/)
- [SpanRender](/api/editor/type-aliases/spanrender/)
- [SpanRenderProps](/api/editor/type-aliases/spanrenderprops/)
- [StyleDefinition](/api/editor/type-aliases/styledefinition/)
- [StyleSchemaType](/api/editor/type-aliases/styleschematype/)
- [TextBlock](/api/editor/type-aliases/textblock/)
- [TextBlockRender](/api/editor/type-aliases/textblockrender/)
- [TextBlockRenderProps](/api/editor/type-aliases/textblockrenderprops/)
## Functions
- [defineAnnotation](/api/editor/functions/defineannotation/)
- [defineBlockObject](/api/editor/functions/defineblockobject/)
- [defineContainer](/api/editor/functions/definecontainer/)
- [defineDecorator](/api/editor/functions/definedecorator/)
- [defineInlineObject](/api/editor/functions/defineinlineobject/)
- [defineSchema](/api/editor/functions/defineschema/)
- [defineSpan](/api/editor/functions/definespan/)
- [defineTextBlock](/api/editor/functions/definetextblock/)
- [keyGenerator](/api/editor/functions/keygenerator/)
- [~~usePortableTextEditor~~](/api/editor/functions/useportabletexteditor/)
- [~~usePortableTextEditorSelection~~](/api/editor/functions/useportabletexteditorselection/)
## Components
- [PortableTextEditable](/api/editor/variables/portabletexteditable/)
- [EditorProvider](/api/editor/functions/editorprovider/)
## Hooks
- [useEditor](/api/editor/functions/useeditor/)
- [useEditorSelector](/api/editor/functions/useeditorselector/)
# AddedAnnotationPaths
> **AddedAnnotationPaths** = `object`
Defined in: packages/editor/src/types/editor.ts:27
## Properties
### ~~markDefPath~~
> **markDefPath**: [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/types/editor.ts:32
:::caution[Deprecated]
An annotation may be applied to multiple blocks, resulting
in multiple `markDef`'s being created. Use `markDefPaths` instead.
:::
***
### markDefPaths
> **markDefPaths**: [`Path`](/api/editor/type-aliases/path/)[]
Defined in: packages/editor/src/types/editor.ts:33
***
### ~~spanPath~~
> **spanPath**: [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/types/editor.ts:39
:::caution[Deprecated]
Does not return anything meaningful since an annotation
can span multiple blocks and spans. If references the span closest
to the focus point of the selection.
:::
# Annotation
> **Annotation** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:356
An annotation registration. `type` is an annotation `_type` declared
in the schema's `annotations` array, or `'*'` to match every
annotation type.
## Properties
### kind
> **kind**: `"annotation"`
Defined in: packages/editor/src/renderers/renderer.types.ts:357
***
### render?
> `optional` **render**: [`AnnotationRender`](/api/editor/type-aliases/annotationrender/)
Defined in: packages/editor/src/renderers/renderer.types.ts:366
Outer render. Two modes:
- omitted: fall through to global registered render (or identity,
the engine default, if no global registration exists)
- function: use this render. The function receives a `renderDefault`
prop that returns identity when called.
***
### type
> **type**: `string`
Defined in: packages/editor/src/renderers/renderer.types.ts:358
# AnnotationDefinition
> **AnnotationDefinition**\<`TBaseDefinition`\> = `TBaseDefinition` & `object`
Defined in: packages/schema/dist/index.d.ts:205
## Type Declaration
### fields?
> `optional` **fields**: `ReadonlyArray`\<[`FieldDefinition`](/api/editor/type-aliases/fielddefinition/)\>
## Type Parameters
### TBaseDefinition
`TBaseDefinition` *extends* [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/)
# AnnotationPath
> **AnnotationPath** = [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/types/paths.ts:43
A path to an annotation markDef on a block.
# AnnotationRender
> **AnnotationRender** = (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:151
## Parameters
### props
[`AnnotationRenderProps`](/api/editor/type-aliases/annotationrenderprops/)
## Returns
`ReactElement`
# AnnotationRenderProps
> **AnnotationRenderProps** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:128
An annotation's render function. Receives the annotation's `markDef`
object and wraps the styled text it applies to. The engine anchors
the text in a `` outside this render regardless of whether a
render is registered; this render's job is the styling wrapper only.
The render is a plain function call, not a component: do not call
hooks in it. When you need hooks, return an element of your own
component: `render: (props) => `.
## Properties
### annotation
> **annotation**: [`PortableTextObject`](/api/editor/interfaces/portabletextobject/)
Defined in: packages/editor/src/renderers/renderer.types.ts:135
The annotation's `markDef` object: `{_key, _type, ...fields}`.
Named `annotation`, not `node`, because `path` addresses the span
leaf carrying the annotation; the markDef itself lives in the block's
`markDefs` array.
***
### children
> **children**: `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:136
***
### focused
> **focused**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:137
***
### path
> **path**: [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/renderers/renderer.types.ts:138
***
### readOnly
> **readOnly**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:139
***
### renderDefault()
> **renderDefault**: (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:146
Render this position with the engine's default wrapper.
See [ContainerRenderProps.renderDefault](/api/editor/type-aliases/containerrenderprops/#renderdefault). The default is
identity: the engine applies no annotation markup of its own.
#### Parameters
##### props
`AnnotationRenderProps`
#### Returns
`ReactElement`
***
### selected
> **selected**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:140
# AnnotationSchemaType
> **AnnotationSchemaType** = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) & `object`
Defined in: packages/schema/dist/index.d.ts:52
## Type Declaration
### fields
> **fields**: `ReadonlyArray`\<[`FieldDefinition`](/api/editor/type-aliases/fielddefinition/)\>
# BaseDefinition
> **BaseDefinition** = `object`
Defined in: packages/schema/dist/index.d.ts:147
## Properties
### name
> **name**: `string`
Defined in: packages/schema/dist/index.d.ts:148
***
### title?
> `optional` **title**: `string`
Defined in: packages/schema/dist/index.d.ts:149
# BlockObject
> **BlockObject** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:375
A non-editable block-level object registration. Identifies a `_type`
whose value renders as a block-level void node (image, embed, etc.).
## Properties
### kind
> **kind**: `"blockObject"`
Defined in: packages/editor/src/renderers/renderer.types.ts:376
***
### render?
> `optional` **render**: [`BlockObjectRender`](/api/editor/type-aliases/blockobjectrender/)
Defined in: packages/editor/src/renderers/renderer.types.ts:384
Outer render. Two modes:
- omitted: fall through to global registered render (or engine default)
- function: use this render. The function receives a `renderDefault`
prop that returns the engine default when called.
***
### type
> **type**: `string`
Defined in: packages/editor/src/renderers/renderer.types.ts:377
# BlockObjectDefinition
> **BlockObjectDefinition**\<`TBaseDefinition`\> = `TBaseDefinition` & `object`
Defined in: packages/schema/dist/index.d.ts:211
## Type Declaration
### fields?
> `optional` **fields**: `ReadonlyArray`\<[`FieldDefinition`](/api/editor/type-aliases/fielddefinition/)\>
## Type Parameters
### TBaseDefinition
`TBaseDefinition` *extends* [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/)
# BlockObjectRender
> **BlockObjectRender** = (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:179
## Parameters
### props
[`BlockObjectRenderProps`](/api/editor/type-aliases/blockobjectrenderprops/)
## Returns
`ReactElement`
# BlockObjectRenderProps
> **BlockObjectRenderProps** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:162
A block object's render function. Receives a non-editable block-level
portable text object. `children` carries an engine-emitted void
spacer that the browser uses to anchor the caret next to the
element. Dropping `children` makes the caret unable to land on the
element.
## Properties
### attributes
> **attributes**: `Record`\<`string`, `unknown`\>
Defined in: packages/editor/src/renderers/renderer.types.ts:163
***
### children
> **children**: `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:164
***
### focused
> **focused**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:165
***
### node
> **node**: [`PortableTextObject`](/api/editor/interfaces/portabletextobject/)
Defined in: packages/editor/src/renderers/renderer.types.ts:166
***
### path
> **path**: [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/renderers/renderer.types.ts:167
***
### readOnly
> **readOnly**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:168
***
### renderDefault()
> **renderDefault**: (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:174
Render this position with the engine's default wrapper.
See [ContainerRenderProps.renderDefault](/api/editor/type-aliases/containerrenderprops/#renderdefault).
#### Parameters
##### props
`BlockObjectRenderProps`
#### Returns
`ReactElement`
***
### selected
> **selected**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:169
# BlockObjectSchemaType
> **BlockObjectSchemaType** = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) & `object`
Defined in: packages/schema/dist/index.d.ts:58
## Type Declaration
### fields
> **fields**: `ReadonlyArray`\<[`FieldDefinition`](/api/editor/type-aliases/fielddefinition/)\>
# BlockOffset
> **BlockOffset** = `object`
Defined in: packages/editor/src/types/block-offset.ts:6
## Properties
### offset
> **offset**: `number`
Defined in: packages/editor/src/types/block-offset.ts:8
***
### path
> **path**: [`BlockPath`](/api/editor/type-aliases/blockpath/)
Defined in: packages/editor/src/types/block-offset.ts:7
# BlockPath
> **BlockPath** = [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/types/paths.ts:36
A path to a block in the value.
# ChildPath
> **ChildPath** = [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/types/paths.ts:50
A path to a child of a text block.
# Container
> **Container** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:225
A container registration. Identifies a block object `_type` whose value
holds editable children in `arrayField`. The optional `of` array carries
nested registrations that override how immediate children of this
container render at this lexical scope.
`of` overrides apply ONE level down only. Children at deeper levels fall
through to global registrations.
The `kind` field is injected by `defineContainer` and discriminates
containers from other registration kinds at runtime.
## Properties
### arrayField
> **arrayField**: `string`
Defined in: packages/editor/src/renderers/renderer.types.ts:228
***
### kind
> **kind**: `"container"`
Defined in: packages/editor/src/renderers/renderer.types.ts:226
***
### of?
> `optional` **of**: `ReadonlyArray`\<`Container` \| [`TextBlock`](/api/editor/type-aliases/textblock/) \| [`BlockObject`](/api/editor/type-aliases/blockobject/)\>
Defined in: packages/editor/src/renderers/renderer.types.ts:240
Block-level positional overrides. Inline-content kinds (`Span`,
`InlineObject`) belong in `TextBlock.of`, not here.
***
### render?
> `optional` **render**: [`ContainerRender`](/api/editor/type-aliases/containerrender/)
Defined in: packages/editor/src/renderers/renderer.types.ts:235
Outer render. Two modes:
- omitted: fall through to global registered render (or engine default)
- function: use this render. The function receives a `renderDefault`
prop that returns the engine default when called.
***
### type
> **type**: `string`
Defined in: packages/editor/src/renderers/renderer.types.ts:227
# ContainerRender
> **ContainerRender** = (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:47
## Parameters
### props
[`ContainerRenderProps`](/api/editor/type-aliases/containerrenderprops/)
## Returns
`ReactElement`
# ContainerRenderProps
> **ContainerRenderProps** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:21
A container's render function receives a node and renders an element
that wraps its editable children. The render is positional: it fires for
nodes of `type` whose parent permits this container at `arrayField`.
`node` is `PortableTextObject` because containers cannot register the
built-in `'span'` or `'block'` types (those are leaves and text blocks
respectively).
## Properties
### attributes
> **attributes**: `Record`\<`string`, `unknown`\>
Defined in: packages/editor/src/renderers/renderer.types.ts:22
***
### children
> **children**: `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:23
***
### focused
> **focused**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:24
***
### node
> **node**: [`PortableTextObject`](/api/editor/interfaces/portabletextobject/)
Defined in: packages/editor/src/renderers/renderer.types.ts:25
***
### path
> **path**: [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/renderers/renderer.types.ts:26
***
### readOnly
> **readOnly**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:27
***
### renderDefault()
> **renderDefault**: (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:42
Render this position with the engine's default wrapper. Call from
inside a custom render to fall back to or wrap the default:
```ts
render: (props) => props.renderDefault(props)
```
The default is the engine's minimal wrapper. It does not chain
back to a globally-registered render: PTE has one user layer plus
positional overrides, and the engine default is the canonical
fallback at any position.
#### Parameters
##### props
`ContainerRenderProps`
#### Returns
`ReactElement`
***
### selected
> **selected**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:28
# Containers
> **Containers** = `ReadonlyMap`\<`string`, [`RegisteredContainer`](/api/editor/type-aliases/registeredcontainer/)\>
Defined in: packages/editor/src/schema/container-types.ts:112
Map of registered editable containers carried on `EditorContext`.
Keyed by bare block-object `_type` (e.g. `'callout'`, `'table'`).
Each entry is a rich [RegisteredContainer](/api/editor/type-aliases/registeredcontainer/) carrying its
`field` plus any positional `of` registrations.
The map preserves positional structure: a `_type` declared inside
a parent's `of` array surfaces as a nested entry on that parent's
`of`, NOT as a separate top-level entry. Path-driven resolution
(see `resolveContainerAt`) reaches positional entries by walking
the tree.
Top-level entries are global fallbacks: when path-driven descent
does not find a positional override, the resolver falls back to the
top-level entry for the type if one is registered.
# Decorator
> **Decorator** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:336
A decorator registration. `type` is a decorator name declared in
the schema's `decorators` array, or `'*'` to match every decorator.
## Properties
### kind
> **kind**: `"decorator"`
Defined in: packages/editor/src/renderers/renderer.types.ts:337
***
### render?
> `optional` **render**: [`DecoratorRender`](/api/editor/type-aliases/decoratorrender/)
Defined in: packages/editor/src/renderers/renderer.types.ts:346
Outer render. Two modes:
- omitted: fall through to global registered render (or identity,
the engine default, if no global registration exists)
- function: use this render. The function receives a `renderDefault`
prop that returns identity when called.
***
### type
> **type**: `string`
Defined in: packages/editor/src/renderers/renderer.types.ts:338
# DecoratorDefinition
> **DecoratorDefinition**\<`TBaseDefinition`\> = `TBaseDefinition`
Defined in: packages/schema/dist/index.d.ts:201
## Type Parameters
### TBaseDefinition
`TBaseDefinition` *extends* [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/)
# DecoratorRender
> **DecoratorRender** = (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:114
## Parameters
### props
[`DecoratorRenderProps`](/api/editor/type-aliases/decoratorrenderprops/)
## Returns
`ReactElement`
# DecoratorRenderProps
> **DecoratorRenderProps** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:90
A decorator's render function. Receives the decorator name and
wraps the styled text it applies to. Range and selection decorations
can split one span into several leaves, so this fires once per
decorator on each leaf, not once per span, nested in the span's
`marks` order.
The render is a plain function call, not a component: do not call
hooks in it. When you need hooks, return an element of your own
component: `render: (props) => `.
## Properties
### children
> **children**: `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:91
***
### decorator
> **decorator**: `string`
Defined in: packages/editor/src/renderers/renderer.types.ts:96
The decorator name, e.g. `'strong'`. A `'*'` render
discriminates on this.
***
### focused
> **focused**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:97
***
### path
> **path**: [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/renderers/renderer.types.ts:101
Path of the span carrying the decorator.
***
### readOnly
> **readOnly**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:102
***
### renderDefault()
> **renderDefault**: (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:109
Render this position with the engine's default wrapper.
See [ContainerRenderProps.renderDefault](/api/editor/type-aliases/containerrenderprops/#renderdefault). The default is
identity: the engine applies no decorator markup of its own.
#### Parameters
##### props
`DecoratorRenderProps`
#### Returns
`ReactElement`
***
### selected
> **selected**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:103
# DecoratorSchemaType
> **DecoratorSchemaType** = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) & `object`
Defined in: packages/schema/dist/index.d.ts:42
## Type Declaration
### ~~value~~
> **value**: `string`
:::caution[Deprecated]
Use `name` instead
:::
# Editor
> **Editor** = `object`
Defined in: packages/editor/src/editor.ts:54
## Properties
### dom
> **dom**: `EditorDom`
Defined in: packages/editor/src/editor.ts:55
***
### getSnapshot()
> **getSnapshot**: () => [`EditorSnapshot`](/api/editor/type-aliases/editorsnapshot/)
Defined in: packages/editor/src/editor.ts:56
#### Returns
[`EditorSnapshot`](/api/editor/type-aliases/editorsnapshot/)
***
### on()
> **on**: \{\<`TType`\>(`type`, `listener`, `options`): `object`; \<`TType`\>(`type`, `listener`, `options?`): `object`; \}
Defined in: packages/editor/src/editor.ts:83
Register an event listener.
With `{batch: true}` the listener is called once per burst with
`Array`, every matching event emitted before control returns to the
event loop (one synchronous `editor.send` worth, normalization included),
in delivery order, on the trailing microtask. That is the same boundary at
which the editor settles its own state, so each call is one fully-applied,
normalized change. Without it (the default), the listener runs
synchronously for every event and receives a single event.
#### Call Signature
> \<`TType`\>(`type`, `listener`, `options`): `object`
##### Type Parameters
###### TType
`TType` *extends* `"*"` \| `"blurred"` \| `"editable"` \| `"focused"` \| `"invalid value"` \| `"mutation"` \| `"operation"` \| `"patch"` \| `"read only"` \| `"ready"` \| `"selection"` \| `"value changed"`
##### Parameters
###### type
`TType`
###### listener
(`events`) => `void`
###### options
###### batch
`true`
##### Returns
`object`
###### unsubscribe()
> **unsubscribe**: () => `void`
###### Returns
`void`
#### Call Signature
> \<`TType`\>(`type`, `listener`, `options?`): `object`
##### Type Parameters
###### TType
`TType` *extends* `"*"` \| `"blurred"` \| `"editable"` \| `"focused"` \| `"invalid value"` \| `"mutation"` \| `"operation"` \| `"patch"` \| `"read only"` \| `"ready"` \| `"selection"` \| `"value changed"`
##### Parameters
###### type
`TType`
###### listener
(`event`) => `void`
###### options?
###### batch?
`false`
##### Returns
`object`
###### unsubscribe()
> **unsubscribe**: () => `void`
###### Returns
`void`
***
### registerBehavior()
> **registerBehavior**: (`config`) => () => `void`
Defined in: packages/editor/src/editor.ts:60
#### Parameters
##### config
###### behavior
`Behavior`
#### Returns
> (): `void`
##### Returns
`void`
***
### registerNode()
> **registerNode**: (`config`) => () => `void`
Defined in: packages/editor/src/editor.ts:70
Register a node renderer. The `node` argument is the result of one
of the `defineX` factories (`defineContainer`, `defineTextBlock`,
`defineSpan`, `defineBlockObject`, `defineInlineObject`,
`defineDecorator`, `defineAnnotation`). Returns a function that
unregisters the node when called.
#### Parameters
##### config
###### node
[`RegistrableNode`](/api/editor/type-aliases/registrablenode/)
#### Returns
> (): `void`
##### Returns
`void`
***
### send()
> **send**: (`event`) => `void`
Defined in: packages/editor/src/editor.ts:71
#### Parameters
##### event
[`EditorEvent`](/api/editor/type-aliases/editorevent/)
#### Returns
`void`
## Methods
### subscribe()
> **subscribe**(`observer`): `object`
Defined in: packages/editor/src/editor.ts:119
Subscribe to editor state changes. The observer's `next` callback fires
with the current `EditorSnapshot` on relevant transitions (selection
updates, content mutations, behavior dispatch, configuration changes).
Notifications are coalesced: a synchronous burst of transitions (e.g. the
many operations one action applies, like undoing a large delete) delivers
a single `next` with the settled snapshot on the next microtask, rather
than one `next` per transition. The snapshot is cumulative, so only
intermediate per-transition states are skipped. To observe every
operation, use `editor.on('operation', ...)`.
The editor has no terminal state and no error path, so `error` and
`complete` are part of the observable contract but never fire. They are
kept for structural compatibility with `useSyncExternalStore`,
`@xstate/react`'s `useSelector`, and other observer-shaped consumers.
#### Parameters
##### observer
###### complete?
() => `void`
###### error?
(`err`) => `void`
###### next?
(`snapshot`) => `void`
#### Returns
`object`
##### unsubscribe()
> **unsubscribe**: () => `void`
###### Returns
`void`
# EditorConfig
> **EditorConfig** = `object`
Defined in: packages/editor/src/editor.ts:13
## Properties
### initialValue?
> `optional` **initialValue**: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[]
Defined in: packages/editor/src/editor.ts:16
***
### keyGenerator()?
> `optional` **keyGenerator**: () => `string`
Defined in: packages/editor/src/editor.ts:14
#### Returns
`string`
***
### readOnly?
> `optional` **readOnly**: `boolean`
Defined in: packages/editor/src/editor.ts:15
***
### schemaDefinition
> **schemaDefinition**: [`SchemaDefinition`](/api/editor/type-aliases/schemadefinition/)
Defined in: packages/editor/src/editor.ts:17
# EditorContext
> **EditorContext** = `object`
Defined in: packages/editor/src/editor/editor-snapshot.ts:11
## Properties
### containers
> **containers**: [`Containers`](/api/editor/type-aliases/containers/)
Defined in: packages/editor/src/editor/editor-snapshot.ts:36
Map of registered editable containers keyed by their bare
block-object `_type` (e.g. `'callout'`, `'table'`).
Each entry is a [RegisteredContainer](/api/editor/type-aliases/registeredcontainer/) carrying `type`,
the array `field` that holds the container's editable children,
and (when present) the nested positional `of` registrations the
engine consults when it descends into the container. The render
callback is engine-internal and not surfaced here.
Only top-level registrations appear as flat entries. A `_type`
registered only inside a parent's `of` is reachable through that
parent's `of`, not as a top-level entry. For position-aware descent,
walk the entries with `getContainerChildren` from
`@portabletext/editor/traversal`.
***
### converters
> **converters**: `Converter`[]
Defined in: packages/editor/src/editor/editor-snapshot.ts:12
***
### keyGenerator()
> **keyGenerator**: () => `string`
Defined in: packages/editor/src/editor/editor-snapshot.ts:13
#### Returns
`string`
***
### readOnly
> **readOnly**: `boolean`
Defined in: packages/editor/src/editor/editor-snapshot.ts:14
***
### schema
> **schema**: [`EditorSchema`](/api/editor/type-aliases/editorschema/)
Defined in: packages/editor/src/editor/editor-snapshot.ts:15
***
### selection
> **selection**: [`EditorSelection`](/api/editor/type-aliases/editorselection/)
Defined in: packages/editor/src/editor/editor-snapshot.ts:16
***
### value
> **value**: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[]
Defined in: packages/editor/src/editor/editor-snapshot.ts:17
# EditorEmittedEvent
> **EditorEmittedEvent** = \{ `event`: `FocusEvent`\<`HTMLDivElement`, `Element`\>; `type`: `"blurred"`; \} \| \{ `type`: `"editable"`; \} \| \{ `event`: `FocusEvent`\<`HTMLDivElement`, `Element`\>; `type`: `"focused"`; \} \| \{ `resolution`: [`InvalidValueResolution`](/api/editor/type-aliases/invalidvalueresolution/) \| `null`; `type`: `"invalid value"`; `value`: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`; \} \| [`MutationEvent`](/api/editor/type-aliases/mutationevent/) \| \{ `operation`: [`Operation`](/api/editor/type-aliases/operation/); `origin`: `"local"` \| `"remote"`; `type`: `"operation"`; \} \| `PatchEvent` \| \{ `type`: `"read only"`; \} \| \{ `type`: `"ready"`; \} \| \{ `selection`: [`EditorSelection`](/api/editor/type-aliases/editorselection/); `type`: `"selection"`; \} \| \{ `type`: `"value changed"`; `value`: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`; \}
Defined in: packages/editor/src/editor/relay.ts:10
## Type Declaration
\{ `event`: `FocusEvent`\<`HTMLDivElement`, `Element`\>; `type`: `"blurred"`; \}
### event
> **event**: `FocusEvent`\<`HTMLDivElement`, `Element`\>
### type
> **type**: `"blurred"`
\{ `type`: `"editable"`; \}
### type
> **type**: `"editable"`
\{ `event`: `FocusEvent`\<`HTMLDivElement`, `Element`\>; `type`: `"focused"`; \}
### event
> **event**: `FocusEvent`\<`HTMLDivElement`, `Element`\>
### type
> **type**: `"focused"`
\{ `resolution`: [`InvalidValueResolution`](/api/editor/type-aliases/invalidvalueresolution/) \| `null`; `type`: `"invalid value"`; `value`: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`; \}
### resolution
> **resolution**: [`InvalidValueResolution`](/api/editor/type-aliases/invalidvalueresolution/) \| `null`
### type
> **type**: `"invalid value"`
### value
> **value**: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`
[`MutationEvent`](/api/editor/type-aliases/mutationevent/)
\{ `operation`: [`Operation`](/api/editor/type-aliases/operation/); `origin`: `"local"` \| `"remote"`; `type`: `"operation"`; \}
### operation
> **operation**: [`Operation`](/api/editor/type-aliases/operation/)
### origin
> **origin**: `"local"` \| `"remote"`
Where the change that produced this operation came from:
`'local'` for changes made in this editor (edits, undo/redo),
`'remote'` for changes applied from the outside (`patches`,
`update value`, and the initial value sync). A normalization fix
(a repaired key, a merged span) reports the origin of the change
that triggered it.
### type
> **type**: `"operation"`
Emitted synchronously for every document-changing operation the
engine applies (`set.selection` is excluded; the `selection` event
serves selection observers), including operations from initial
value sync and normalization, unlike `patch` and `mutation`
events, which are held back until the editor is dirty. Do not
dispatch editor events from a listener; read current state via
`editor.getSnapshot()`.
The `operation` object is the engine's own, passed by reference:
treat it as read-only and copy anything you retain. Normalization
fix operations are delivered adjacent to the operation that
triggered them, but not in a guaranteed order; see the
[Operation](/api/editor/type-aliases/operation/) docs for the delivery-order contract. Subscribers
attached after setup receive only subsequent operations: seed
derived state from `editor.getSnapshot()` when subscribing, then
apply deltas.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
`PatchEvent`
\{ `type`: `"read only"`; \}
### type
> **type**: `"read only"`
\{ `type`: `"ready"`; \}
### type
> **type**: `"ready"`
\{ `selection`: [`EditorSelection`](/api/editor/type-aliases/editorselection/); `type`: `"selection"`; \}
### selection
> **selection**: [`EditorSelection`](/api/editor/type-aliases/editorselection/)
### type
> **type**: `"selection"`
\{ `type`: `"value changed"`; `value`: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`; \}
### type
> **type**: `"value changed"`
### value
> **value**: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`
# EditorEvent
> **EditorEvent** = `ExternalEditorEvent` \| `ExternalBehaviorEvent` \| \{ `type`: `"update value"`; `value`: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`; \}
Defined in: packages/editor/src/editor.ts:23
## Type Declaration
`ExternalEditorEvent`
`ExternalBehaviorEvent`
\{ `type`: `"update value"`; `value`: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`; \}
### type
> **type**: `"update value"`
Hands the editor the host's latest snapshot of the value so it can
reconcile. This is not a setter: the snapshot is compared against
the previous snapshot the host sent, not against the editor's
current content, and only the remote change that comparison implies
is applied. A snapshot equal to the previous one is ignored, even
if the editor's content has since diverged from it through local
edits.
Reconciliation is not an edit: it emits no `patch` or `mutation`
events and adds no history step. While local changes are in
flight, it is deferred until they have flushed. `undefined` and
`[]` are the same empty snapshot: sending either when the previous
snapshot was also empty is a no-op and never clears locally typed
content.
To change content programmatically, use editing events so the
change flows through behaviors and emits patches; to reset the
editor wholesale, remount it with a fresh `initialValue`.
### value
> **value**: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`
# EditorProviderProps
> **EditorProviderProps** = `object`
Defined in: packages/editor/src/editor/editor-provider.tsx:16
## Properties
### children?
> `optional` **children**: `React.ReactNode`
Defined in: packages/editor/src/editor/editor-provider.tsx:18
***
### initialConfig
> **initialConfig**: [`EditorConfig`](/api/editor/type-aliases/editorconfig/)
Defined in: packages/editor/src/editor/editor-provider.tsx:17
# EditorSchema
> **EditorSchema** = `Schema`
Defined in: packages/editor/src/editor/editor-schema.ts:6
# EditorSelection
> **EditorSelection** = \{ `anchor`: [`EditorSelectionPoint`](/api/editor/type-aliases/editorselectionpoint/); `backward?`: `boolean`; `focus`: [`EditorSelectionPoint`](/api/editor/type-aliases/editorselectionpoint/); \} \| `null`
Defined in: packages/editor/src/types/editor.ts:101
# EditorSelectionPoint
> **EditorSelectionPoint** = `object`
Defined in: packages/editor/src/types/editor.ts:99
## Properties
### offset
> **offset**: `number`
Defined in: packages/editor/src/types/editor.ts:99
***
### path
> **path**: [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/types/editor.ts:99
# EditorSelector
> **EditorSelector**\<`TSelected`\> = (`snapshot`) => `TSelected`
Defined in: packages/editor/src/editor/editor-selector.ts:13
## Type Parameters
### TSelected
`TSelected`
## Parameters
### snapshot
[`EditorSnapshot`](/api/editor/type-aliases/editorsnapshot/)
## Returns
`TSelected`
# EditorSnapshot
> **EditorSnapshot** = `object`
Defined in: packages/editor/src/editor/editor-snapshot.ts:42
## Properties
### blockIndexMap
> **blockIndexMap**: `ReadonlyMap`\<`string`, `number`\>
Defined in: packages/editor/src/editor/editor-snapshot.ts:44
***
### context
> **context**: [`EditorContext`](/api/editor/type-aliases/editorcontext/)
Defined in: packages/editor/src/editor/editor-snapshot.ts:43
***
### decoratorState
> **decoratorState**: `Record`\<`string`, `boolean` \| `undefined`\>
Defined in: packages/editor/src/editor/editor-snapshot.ts:49
Subject to change
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# FieldDefinition
> **FieldDefinition** = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) & `object` \| [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) & `object`
Defined in: packages/schema/dist/index.d.ts:138
# HotkeyOptions
> **HotkeyOptions** = `object`
Defined in: packages/editor/src/types/options.ts:7
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### custom?
> `optional` **custom**: `Record`\<`string`, (`event`, `editor`) => `void`\>
Defined in: packages/editor/src/types/options.ts:9
***
### marks?
> `optional` **marks**: `Record`\<`string`, `string`\>
Defined in: packages/editor/src/types/options.ts:8
# InlineObject
> **InlineObject** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:393
A non-editable inline object registration. Identifies a `_type` whose
value renders as an inline void node (mention, inline image, etc.).
## Properties
### kind
> **kind**: `"inlineObject"`
Defined in: packages/editor/src/renderers/renderer.types.ts:394
***
### render?
> `optional` **render**: [`InlineObjectRender`](/api/editor/type-aliases/inlineobjectrender/)
Defined in: packages/editor/src/renderers/renderer.types.ts:402
Outer render. Two modes:
- omitted: fall through to global registered render (or engine default)
- function: use this render. The function receives a `renderDefault`
prop that returns the engine default when called.
***
### type
> **type**: `string`
Defined in: packages/editor/src/renderers/renderer.types.ts:395
# InlineObjectDefinition
> **InlineObjectDefinition**\<`TBaseDefinition`\> = `TBaseDefinition` & `object`
Defined in: packages/schema/dist/index.d.ts:217
## Type Declaration
### fields?
> `optional` **fields**: `ReadonlyArray`\<[`FieldDefinition`](/api/editor/type-aliases/fielddefinition/)\>
## Type Parameters
### TBaseDefinition
`TBaseDefinition` *extends* [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/)
# InlineObjectRender
> **InlineObjectRender** = (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:207
## Parameters
### props
[`InlineObjectRenderProps`](/api/editor/type-aliases/inlineobjectrenderprops/)
## Returns
`ReactElement`
# InlineObjectRenderProps
> **InlineObjectRenderProps** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:190
An inline object's render function. Receives a non-editable inline
portable text object. `children` carries an engine-emitted void
spacer that the browser uses to anchor the caret next to the
element. Dropping `children` makes the caret unable to land on the
element.
## Properties
### attributes
> **attributes**: `Record`\<`string`, `unknown`\>
Defined in: packages/editor/src/renderers/renderer.types.ts:191
***
### children
> **children**: `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:192
***
### focused
> **focused**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:193
***
### node
> **node**: [`PortableTextObject`](/api/editor/interfaces/portabletextobject/)
Defined in: packages/editor/src/renderers/renderer.types.ts:194
***
### path
> **path**: [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/renderers/renderer.types.ts:195
***
### readOnly
> **readOnly**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:196
***
### renderDefault()
> **renderDefault**: (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:202
Render this position with the engine's default wrapper.
See [ContainerRenderProps.renderDefault](/api/editor/type-aliases/containerrenderprops/#renderdefault).
#### Parameters
##### props
`InlineObjectRenderProps`
#### Returns
`ReactElement`
***
### selected
> **selected**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:197
# InlineObjectSchemaType
> **InlineObjectSchemaType** = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) & `object`
Defined in: packages/schema/dist/index.d.ts:64
## Type Declaration
### fields
> **fields**: `ReadonlyArray`\<[`FieldDefinition`](/api/editor/type-aliases/fielddefinition/)\>
# InvalidValueResolution
> **InvalidValueResolution** = `object`
Defined in: packages/editor/src/types/editor.ts:110
The editor has invalid data in the value that can be resolved by the user
## Properties
### action
> **action**: `string`
Defined in: packages/editor/src/types/editor.ts:114
***
### autoResolve?
> `optional` **autoResolve**: `boolean`
Defined in: packages/editor/src/types/editor.ts:111
***
### description
> **description**: `string`
Defined in: packages/editor/src/types/editor.ts:113
***
### i18n
> **i18n**: `object`
Defined in: packages/editor/src/types/editor.ts:124
i18n keys for the description and action
These are in addition to the description and action properties, to decouple the editor from
the i18n system, and allow usage without it. The i18n keys take precedence over the
description and action properties, if i18n framework is available.
#### action
> **action**: `` `inputs.portable-text.invalid-value.${Lowercase}.action` ``
#### description
> **description**: `` `inputs.portable-text.invalid-value.${Lowercase}.description` ``
#### values?
> `optional` **values**: `Record`\<`string`, `string` \| `number` \| `string`[]\>
***
### item
> **item**: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/) \| [`PortableTextChild`](/api/editor/type-aliases/portabletextchild/) \| `undefined`
Defined in: packages/editor/src/types/editor.ts:115
***
### patches
> **patches**: [`Patch`](/api/editor/type-aliases/patch/)[]
Defined in: packages/editor/src/types/editor.ts:112
# ListDefinition
> **ListDefinition**\<`TBaseDefinition`\> = `TBaseDefinition`
Defined in: packages/schema/dist/index.d.ts:197
## Type Parameters
### TBaseDefinition
`TBaseDefinition` *extends* [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/)
# ListSchemaType
> **ListSchemaType** = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) & `object`
Defined in: packages/schema/dist/index.d.ts:32
## Type Declaration
### ~~value~~
> **value**: `string`
:::caution[Deprecated]
Use `name` instead
:::
# MutationEvent
> **MutationEvent** = `object`
Defined in: packages/editor/src/editor/relay.ts:79
## Properties
### patches
> **patches**: [`Patch`](/api/editor/type-aliases/patch/)[]
Defined in: packages/editor/src/editor/relay.ts:81
***
### type
> **type**: `"mutation"`
Defined in: packages/editor/src/editor/relay.ts:80
***
### value
> **value**: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`
Defined in: packages/editor/src/editor/relay.ts:82
# OfDefinition
> **OfDefinition** = `BlockOfDefinition` \| `InlineObjectOfDefinition` \| `ReferenceOfDefinition`
Defined in: packages/schema/dist/index.d.ts:80
Describes a member type within an array field's `of`.
Three forms:
- `BlockOfDefinition` (`type: 'block'`) - declares a nested text block,
with PTE sub-schema configurable inline.
- `InlineObjectOfDefinition` (`type: 'object'`) - inline-declares an
object shape at this position. `name` is the type identity; `fields`
defines the shape.
- `ReferenceOfDefinition` (`type: `) - a bare reference to a type
declared in `blockObjects` or `inlineObjects` at the schema root.
# OnCopyFn
> **OnCopyFn** = (`event`) => `undefined` \| `unknown`
Defined in: packages/editor/src/types/editor.ts:161
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### event
`ClipboardEvent`\<`HTMLDivElement` \| `HTMLSpanElement`\>
## Returns
`undefined` \| `unknown`
# OnPasteFn
> **OnPasteFn** = (`data`) => [`OnPasteResultOrPromise`](/api/editor/type-aliases/onpasteresultorpromise/)
Defined in: packages/editor/src/types/editor.ts:158
It is encouraged not to return `Promise` from the `OnPasteFn` as
a mechanism to fall back to the native paste behaviour. This doesn't work in
all cases. Always return plain `undefined` if possible.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### data
[`PasteData`](/api/editor/interfaces/pastedata/)
## Returns
[`OnPasteResultOrPromise`](/api/editor/type-aliases/onpasteresultorpromise/)
# OnPasteResult
> **OnPasteResult** = \{ `insert?`: `TypedObject`[]; `path?`: [`Path`](/api/editor/type-aliases/path/); \} \| `undefined`
Defined in: packages/editor/src/types/editor.ts:132
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# OnPasteResultOrPromise
> **OnPasteResultOrPromise** = [`OnPasteResult`](/api/editor/type-aliases/onpasteresult/) \| `Promise`\<[`OnPasteResult`](/api/editor/type-aliases/onpasteresult/)\>
Defined in: packages/editor/src/types/editor.ts:142
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# Operation
> **Operation** = `InsertOperation` \| `InsertTextOperation` \| `RemoveTextOperation` \| `SetOperation` \| `UnsetOperation`
Defined in: packages/editor/src/types/operation.ts:41
The document-changing operations emitted through
`editor.on('operation', ...)`. Every change to the editor (local edits,
remote patches, value sync, normalization fixes, undo/redo) is expressed
as a sequence of these five operations.
The vocabulary is closed: there are exactly five, listed explicitly so
that a new engine operation never becomes public surface by default, and
the dot-named ones (`insert.text`, `remove.text`) are not namespaces that
grow members.
Selection movements are not emitted on this stream; subscribe to the
`selection` event instead.
Operation objects are the engine's own, passed by reference: treat them
as read-only and copy anything you retain beyond the listener call.
Delivery order: normalization fix operations are delivered adjacent to
the operation that triggered them, but whether a fix arrives before or
after its trigger depends on how the trigger was applied (a fix
re-enters the engine's apply, so an unbatched trigger delivers the fix
first; batched applies deliver fixes after the batch). Do not assume
delivery order equals application order under normalization: seed
derived state from `editor.getSnapshot()` and recompute on change
rather than replaying deltas blindly.
`inverse`, when present, reflects what the engine itself needs to make
the operation reversible. Its presence follows the engine's history
policy and is not a stable per-operation contract.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# Patch
> **Patch** = `SetPatch` \| `SetIfMissingPatch` \| `UnsetPatch` \| `InsertPatch` \| `DiffMatchPatch` \| `IncPatch` \| `DecPatch`
Defined in: packages/patches/dist/index.d.ts:69
# PatchesEvent
> **PatchesEvent** = `object`
Defined in: packages/editor/src/editor/editor-machine.ts:42
## Properties
### patches
> **patches**: [`Patch`](/api/editor/type-aliases/patch/)[]
Defined in: packages/editor/src/editor/editor-machine.ts:44
***
### snapshot
> **snapshot**: [`PortableTextBlock`](/api/editor/type-aliases/portabletextblock/)[] \| `undefined`
Defined in: packages/editor/src/editor/editor-machine.ts:45
***
### type
> **type**: `"patches"`
Defined in: packages/editor/src/editor/editor-machine.ts:43
# Path
> **Path** = `PathSegment`[]
Defined in: packages/editor/src/types/paths.ts:29
A path is an array of path segments that describes a location in a document.
# PortableTextBlock
> **PortableTextBlock** = [`PortableTextTextBlock`](/api/editor/interfaces/portabletexttextblock/) \| [`PortableTextObject`](/api/editor/interfaces/portabletextobject/)
Defined in: packages/schema/dist/index.d.ts:257
# PortableTextChild
> **PortableTextChild** = [`PortableTextSpan`](/api/editor/interfaces/portabletextspan/) \| [`PortableTextObject`](/api/editor/interfaces/portabletextobject/)
Defined in: packages/schema/dist/index.d.ts:302
# PortableTextEditableProps
> **PortableTextEditableProps** = `Omit`\<`TextareaHTMLAttributes`\<`HTMLDivElement`\>, `"onPaste"` \| `"onCopy"` \| `"onBeforeInput"`\> & `object`
Defined in: packages/editor/src/editor/Editable.tsx:53
## Type Declaration
### hotkeys?
> `optional` **hotkeys**: [`HotkeyOptions`](/api/editor/type-aliases/hotkeyoptions/)
### onBeforeInput()?
> `optional` **onBeforeInput**: (`event`) => `void`
#### Parameters
##### event
`InputEvent`
#### Returns
`void`
### onCopy?
> `optional` **onCopy**: [`OnCopyFn`](/api/editor/type-aliases/oncopyfn/)
### onPaste?
> `optional` **onPaste**: [`OnPasteFn`](/api/editor/type-aliases/onpastefn/)
### rangeDecorations?
> `optional` **rangeDecorations**: [`RangeDecoration`](/api/editor/interfaces/rangedecoration/)[]
### ref?
> `optional` **ref**: `React.Ref`\<`HTMLDivElement`\>
### renderPlaceholder?
> `optional` **renderPlaceholder**: [`RenderPlaceholderFunction`](/api/editor/type-aliases/renderplaceholderfunction/)
### scrollSelectionIntoView?
> `optional` **scrollSelectionIntoView**: [`ScrollSelectionIntoViewFunction`](/api/editor/type-aliases/scrollselectionintoviewfunction/)
### selection?
> `optional` **selection**: [`EditorSelection`](/api/editor/type-aliases/editorselection/)
### spellCheck?
> `optional` **spellCheck**: `boolean`
# RegisteredBlockObject
> **RegisteredBlockObject** = `object`
Defined in: packages/editor/src/schema/container-types.ts:64
Public view of a registered block object, surfaced inside a
containing [RegisteredContainer](/api/editor/type-aliases/registeredcontainer/)'s `of` array as a positional
registration. The render function is engine-internal.
## Properties
### kind
> **kind**: `"blockObject"`
Defined in: packages/editor/src/schema/container-types.ts:65
***
### type
> **type**: `string`
Defined in: packages/editor/src/schema/container-types.ts:66
# RegisteredContainer
> **RegisteredContainer** = `object`
Defined in: packages/editor/src/schema/container-types.ts:33
Public view of a registered editable container, surfaced on
[EditorContext.containers](/api/editor/type-aliases/editorcontext/#containers).
Two array properties named `of` live on the same entry with
different semantics:
- `field.of` is the SCHEMA-DECLARED list of types this container's
child field accepts (from `@portabletext/schema`'s
`OfDefinition`). Tells you what the schema permits as children.
- `of` (top-level on `RegisteredContainer`) is the list of
POSITIONAL CHILD REGISTRATIONS - nested
[RegisteredContainer](/api/editor/type-aliases/registeredcontainer/) or [RegisteredPositional](/api/editor/type-aliases/registeredpositional/)
entries - that override the global registration when the engine
descends into this parent. Tells you which child renderings are
scoped to this parent.
The full container registration (including the render callback)
lives on an engine-internal map and is not exposed on the public
context.
Two top-level entries with the same `_type` cannot coexist - the
register handler warns on duplicates. But the SAME `_type`
registered in two different parents' `of` arrays is supported as
a feature; `resolveContainerAt` walks the positional tree using
the path to return the entry that applies at a given position.
## Properties
### field
> **field**: [`FieldDefinition`](/api/editor/type-aliases/fielddefinition/) & `object`
Defined in: packages/editor/src/schema/container-types.ts:36
#### Type Declaration
##### of
> **of**: `ReadonlyArray`\<[`OfDefinition`](/api/editor/type-aliases/ofdefinition/)\>
##### type
> **type**: `"array"`
***
### kind
> **kind**: `"container"`
Defined in: packages/editor/src/schema/container-types.ts:34
***
### of?
> `optional` **of**: `ReadonlyArray`\<`RegisteredContainer` \| [`RegisteredPositional`](/api/editor/type-aliases/registeredpositional/)\>
Defined in: packages/editor/src/schema/container-types.ts:40
***
### type
> **type**: `string`
Defined in: packages/editor/src/schema/container-types.ts:35
# RegisteredInlineObject
> **RegisteredInlineObject** = `object`
Defined in: packages/editor/src/schema/container-types.ts:76
Public view of a registered inline object, surfaced inside a
containing [RegisteredContainer](/api/editor/type-aliases/registeredcontainer/)'s `of` array as a positional
registration. The render function is engine-internal.
## Properties
### kind
> **kind**: `"inlineObject"`
Defined in: packages/editor/src/schema/container-types.ts:77
***
### type
> **type**: `string`
Defined in: packages/editor/src/schema/container-types.ts:78
# RegisteredPositional
> **RegisteredPositional** = [`RegisteredSpan`](/api/editor/type-aliases/registeredspan/) \| [`RegisteredBlockObject`](/api/editor/type-aliases/registeredblockobject/) \| [`RegisteredInlineObject`](/api/editor/type-aliases/registeredinlineobject/)
Defined in: packages/editor/src/schema/container-types.ts:88
Union of non-container positional registrations that may appear in
a [RegisteredContainer](/api/editor/type-aliases/registeredcontainer/)'s `of` array. Text-block registrations
are NOT included here and do not appear on the containers tree.
# RegisteredSpan
> **RegisteredSpan** = `object`
Defined in: packages/editor/src/schema/container-types.ts:52
Public view of a registered span, surfaced inside a containing
[RegisteredContainer](/api/editor/type-aliases/registeredcontainer/)'s `of` array as a positional
registration. The render function is engine-internal.
## Properties
### kind
> **kind**: `"span"`
Defined in: packages/editor/src/schema/container-types.ts:53
***
### type
> **type**: `string`
Defined in: packages/editor/src/schema/container-types.ts:54
# RegistrableNode
> **RegistrableNode** = [`Container`](/api/editor/type-aliases/container/) \| [`TextBlock`](/api/editor/type-aliases/textblock/) \| [`Span`](/api/editor/type-aliases/span/) \| [`BlockObject`](/api/editor/type-aliases/blockobject/) \| [`InlineObject`](/api/editor/type-aliases/inlineobject/) \| [`Decorator`](/api/editor/type-aliases/decorator/) \| [`Annotation`](/api/editor/type-aliases/annotation/)
Defined in: packages/editor/src/renderers/renderer.types.ts:411
The discriminated union of every registration accepted by
`editor.registerNode` and the `` component.
# RenderEditableFunction
> **RenderEditableFunction** = (`props`) => `JSX.Element`
Defined in: packages/editor/src/types/editor.ts:166
## Parameters
### props
[`PortableTextEditableProps`](/api/editor/type-aliases/portabletexteditableprops/)
## Returns
`JSX.Element`
# RenderPlaceholderFunction
> **RenderPlaceholderFunction** = () => `React.ReactNode`
Defined in: packages/editor/src/types/editor.ts:171
## Returns
`React.ReactNode`
# SchemaDefinition
> **SchemaDefinition** = `object`
Defined in: packages/schema/dist/index.d.ts:154
## Properties
### annotations?
> `optional` **annotations**: `ReadonlyArray`\<[`AnnotationDefinition`](/api/editor/type-aliases/annotationdefinition/)\>
Defined in: packages/schema/dist/index.d.ts:162
***
### block?
> `optional` **block**: `object`
Defined in: packages/schema/dist/index.d.ts:155
#### fields?
> `optional` **fields**: `ReadonlyArray`\<[`FieldDefinition`](/api/editor/type-aliases/fielddefinition/)\>
#### name?
> `optional` **name**: `string`
***
### blockObjects?
> `optional` **blockObjects**: `ReadonlyArray`\<[`BlockObjectDefinition`](/api/editor/type-aliases/blockobjectdefinition/)\>
Defined in: packages/schema/dist/index.d.ts:163
***
### decorators?
> `optional` **decorators**: `ReadonlyArray`\<[`DecoratorDefinition`](/api/editor/type-aliases/decoratordefinition/)\>
Defined in: packages/schema/dist/index.d.ts:161
***
### inlineObjects?
> `optional` **inlineObjects**: `ReadonlyArray`\<[`InlineObjectDefinition`](/api/editor/type-aliases/inlineobjectdefinition/)\>
Defined in: packages/schema/dist/index.d.ts:164
***
### lists?
> `optional` **lists**: `ReadonlyArray`\<[`ListDefinition`](/api/editor/type-aliases/listdefinition/)\>
Defined in: packages/schema/dist/index.d.ts:160
***
### styles?
> `optional` **styles**: `ReadonlyArray`\<[`StyleDefinition`](/api/editor/type-aliases/styledefinition/)\>
Defined in: packages/schema/dist/index.d.ts:159
# ScrollSelectionIntoViewFunction
> **ScrollSelectionIntoViewFunction** = (`editor`, `domRange`) => `void`
Defined in: packages/editor/src/types/editor.ts:174
## Parameters
### editor
[`PortableTextEditor`](/api/editor/classes/portabletexteditor/)
### domRange
`globalThis.Range`
## Returns
`void`
# Span
> **Span** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:318
A span registration. The span `_type` is `'span'` at the top level.
Positional overrides nested in a container's `of` array can register
a different `_type` for a span-like inline at that lexical scope
(e.g. a `code-span` inside a `code-block`).
## Properties
### kind
> **kind**: `"span"`
Defined in: packages/editor/src/renderers/renderer.types.ts:319
***
### render?
> `optional` **render**: [`SpanRender`](/api/editor/type-aliases/spanrender/)
Defined in: packages/editor/src/renderers/renderer.types.ts:327
Outer render. Two modes:
- omitted: fall through to global registered render (or engine default)
- function: use this render. The function receives a `renderDefault`
prop that returns the engine default when called.
***
### type
> **type**: `string`
Defined in: packages/editor/src/renderers/renderer.types.ts:320
# SpanRender
> **SpanRender** = (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:75
## Parameters
### props
[`SpanRenderProps`](/api/editor/type-aliases/spanrenderprops/)
## Returns
`ReactElement`
# SpanRenderProps
> **SpanRenderProps** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:58
A span's render function. Receives a portable text span node and
wraps it. `children` carries the styled text already decorated by
the decorator/annotation renders (registered via `defineDecorator`/
`defineAnnotation`). Range decorations wrap this render's output
from the outside, so they are not part of `children`.
## Properties
### attributes
> **attributes**: `Record`\<`string`, `unknown`\>
Defined in: packages/editor/src/renderers/renderer.types.ts:59
***
### children
> **children**: `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:60
***
### focused
> **focused**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:61
***
### node
> **node**: [`PortableTextSpan`](/api/editor/interfaces/portabletextspan/)
Defined in: packages/editor/src/renderers/renderer.types.ts:62
***
### path
> **path**: [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/renderers/renderer.types.ts:63
***
### readOnly
> **readOnly**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:64
***
### renderDefault()
> **renderDefault**: (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:70
Render this position with the engine's default wrapper.
See [ContainerRenderProps.renderDefault](/api/editor/type-aliases/containerrenderprops/#renderdefault).
#### Parameters
##### props
`SpanRenderProps`
#### Returns
`ReactElement`
***
### selected
> **selected**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:65
# StyleDefinition
> **StyleDefinition**\<`TBaseDefinition`\> = `TBaseDefinition`
Defined in: packages/schema/dist/index.d.ts:193
## Type Parameters
### TBaseDefinition
`TBaseDefinition` *extends* [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/)
# StyleSchemaType
> **StyleSchemaType** = [`BaseDefinition`](/api/editor/type-aliases/basedefinition/) & `object`
Defined in: packages/schema/dist/index.d.ts:22
## Type Declaration
### ~~value~~
> **value**: `string`
:::caution[Deprecated]
Use `name` instead
:::
# TextBlock
> **TextBlock** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:260
A text block registration. The text block `_type` is `'block'` at the
top level. Positional overrides nested in a container's `of` array can
register a different `_type` to render at that lexical scope.
`defineTextBlock` opts the text block into the new render pipeline.
The consumer's `render` callback owns the outer wrapper entirely: the
engine emits `data-pt-*` attributes only, no `pt-*` CSS classes and no
legacy `data-block-*` attributes.
Span-level rendering - decorator and annotation registrations,
`renderPlaceholder`, and range decorations - keeps working. It
fires on the spans inside `children` regardless of which text
block outer wrapper renders them.
## Properties
### kind
> **kind**: `"textBlock"`
Defined in: packages/editor/src/renderers/renderer.types.ts:261
***
### of?
> `optional` **of**: `ReadonlyArray`\<[`Span`](/api/editor/type-aliases/span/) \| [`InlineObject`](/api/editor/type-aliases/inlineobject/) \| [`Decorator`](/api/editor/type-aliases/decorator/) \| [`Annotation`](/api/editor/type-aliases/annotation/)\>
Defined in: packages/editor/src/renderers/renderer.types.ts:279
Inline-content positional overrides. A `Span` or `InlineObject`
placed here scopes the inline render to this text block (or any
text block of this `type` if registered at the top level).
`Decorator` and `Annotation` entries scope those renders the
same way: the decorator or annotation renders through this entry
inside the text block, and through the global registration
everywhere else.
***
### render?
> `optional` **render**: [`TextBlockRender`](/api/editor/type-aliases/textblockrender/)
Defined in: packages/editor/src/renderers/renderer.types.ts:269
Outer render. Two modes:
- omitted: fall through to global registered render (or engine default)
- function: use this render. The function receives a `renderDefault`
prop that returns the engine default when called.
***
### type
> **type**: `string`
Defined in: packages/editor/src/renderers/renderer.types.ts:262
# TextBlockRender
> **TextBlockRender** = (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:308
## Parameters
### props
[`TextBlockRenderProps`](/api/editor/type-aliases/textblockrenderprops/)
## Returns
`ReactElement`
# TextBlockRenderProps
> **TextBlockRenderProps** = `object`
Defined in: packages/editor/src/renderers/renderer.types.ts:291
Text block render function. `children` carries the rendered spans -
decorator and annotation registrations, `renderPlaceholder`, and
range decorations have already fired at the leaf level. The render's
job is the outer wrapper element and any block-level composition
(style, list-item) the consumer wants.
## Properties
### attributes
> **attributes**: `Record`\<`string`, `unknown`\>
Defined in: packages/editor/src/renderers/renderer.types.ts:292
***
### children
> **children**: `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:293
***
### focused
> **focused**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:294
***
### node
> **node**: [`PortableTextTextBlock`](/api/editor/interfaces/portabletexttextblock/)
Defined in: packages/editor/src/renderers/renderer.types.ts:295
***
### path
> **path**: [`Path`](/api/editor/type-aliases/path/)
Defined in: packages/editor/src/renderers/renderer.types.ts:296
***
### readOnly
> **readOnly**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:297
***
### renderDefault()
> **renderDefault**: (`props`) => `ReactElement`
Defined in: packages/editor/src/renderers/renderer.types.ts:303
Render this position with the engine's default wrapper.
See [ContainerRenderProps.renderDefault](/api/editor/type-aliases/containerrenderprops/#renderdefault).
#### Parameters
##### props
`TextBlockRenderProps`
#### Returns
`ReactElement`
***
### selected
> **selected**: `boolean`
Defined in: packages/editor/src/renderers/renderer.types.ts:298
# PortableTextEditable
> `const` **PortableTextEditable**: `ForwardRefExoticComponent`\<`Omit`\<[`PortableTextEditableProps`](/api/editor/type-aliases/portabletexteditableprops/), `"ref"`\> & `RefAttributes`\<`Omit`\<`HTMLDivElement`, `"as"` \| `"onPaste"` \| `"onBeforeInput"`\>\>\>
Defined in: packages/editor/src/editor/Editable.tsx:89
The core component that renders the editor. Must be placed within the [EditorProvider](/api/editor/functions/editorprovider/) component.
## Example
```tsx
import { PortableTextEditable, EditorProvider } from '@portabletext/editor'
function MyComponent() {
return (
)
}
```
# createKeyboardShortcut
> **createKeyboardShortcut**\<`TKeyboardEvent`\>(`definition`): [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`TKeyboardEvent`\>
Defined in: keyboard-shortcuts.ts:86
Creates a `KeyboardShortcut` from a `KeyboardShortcutDefinition`.
`default` keyboard event definitions are required while the `apple`
keyboard event definitions are optional.
## Type Parameters
### TKeyboardEvent
`TKeyboardEvent` *extends* `Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\> = `Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>
## Parameters
### definition
[`KeyboardShortcutDefinition`](/api/keyboard-shortcuts/type-aliases/keyboardshortcutdefinition/)
## Returns
[`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`TKeyboardEvent`\>
## Example
```typescript
const shortcut = createKeyboardShortcut({
default: [{
key: 'B',
alt: false,
ctrl: true,
meta: false,
shift: false,
}],
apple: [{
key: 'B',
alt: false,
ctrl: false,
meta: true,
shift: false,
}],
})
```
# @portabletext/keyboard-shortcuts
## Type Aliases
- [KeyboardEventDefinition](/api/keyboard-shortcuts/type-aliases/keyboardeventdefinition/)
- [KeyboardShortcut](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)
- [KeyboardShortcutDefinition](/api/keyboard-shortcuts/type-aliases/keyboardshortcutdefinition/)
## Variables
- [blockquote](/api/keyboard-shortcuts/variables/blockquote/)
- [bold](/api/keyboard-shortcuts/variables/bold/)
- [code](/api/keyboard-shortcuts/variables/code/)
- [h1](/api/keyboard-shortcuts/variables/h1/)
- [h2](/api/keyboard-shortcuts/variables/h2/)
- [h3](/api/keyboard-shortcuts/variables/h3/)
- [h4](/api/keyboard-shortcuts/variables/h4/)
- [h5](/api/keyboard-shortcuts/variables/h5/)
- [h6](/api/keyboard-shortcuts/variables/h6/)
- [italic](/api/keyboard-shortcuts/variables/italic/)
- [link](/api/keyboard-shortcuts/variables/link/)
- [normal](/api/keyboard-shortcuts/variables/normal/)
- [redo](/api/keyboard-shortcuts/variables/redo/)
- [strikeThrough](/api/keyboard-shortcuts/variables/strikethrough/)
- [underline](/api/keyboard-shortcuts/variables/underline/)
- [undo](/api/keyboard-shortcuts/variables/undo/)
## Functions
- [createKeyboardShortcut](/api/keyboard-shortcuts/functions/createkeyboardshortcut/)
# KeyboardEventDefinition
> **KeyboardEventDefinition** = \{ `code`: `KeyboardEvent`\[`"code"`\]; `key`: `KeyboardEvent`\[`"key"`\]; \} \| \{ `code?`: `undefined`; `key`: `KeyboardEvent`\[`"key"`\]; \} \| \{ `code`: `KeyboardEvent`\[`"code"`\]; `key?`: `undefined`; \} & `object`
Defined in: keyboard-event-definition.ts:25
A keyboard event definition that can be used to create a keyboard shortcut.
At least one of `key` or `code` must be provided while the `alt`, `ctrl`,
`meta`, and `shift` modifier configurations are optional.
The `key` represents a https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
and is treated as case-insensitive.
The `code` represents a https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
and is treated as case-insensitive.
## Type Declaration
### alt?
> `optional` **alt**: `KeyboardEvent`\[`"altKey"`\]
### ctrl?
> `optional` **ctrl**: `KeyboardEvent`\[`"ctrlKey"`\]
### meta?
> `optional` **meta**: `KeyboardEvent`\[`"metaKey"`\]
### shift?
> `optional` **shift**: `KeyboardEvent`\[`"shiftKey"`\]
## Example
```typescript
const boldEvent: KeyboardEventDefinition = {
key: 'B',
alt: false,
ctrl: true,
meta: false,
shift: false,
}
```
# KeyboardShortcut
> **KeyboardShortcut**\<`TKeyboardEvent`\> = `object`
Defined in: keyboard-shortcuts.ts:46
A resolved keyboard shortcut for the current platform that has been
processed by `createKeyboardShortcut(...)` to select the appropriate
platform-specific key combination. The `guard` function determines if the
shortcut applies to the current `KeyboardEvent`, while `keys` contains the
display-friendly key combination for the current platform.
## Type Parameters
### TKeyboardEvent
`TKeyboardEvent` *extends* `Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\> = `Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>
## Properties
### guard()
> **guard**: (`event`) => `boolean`
Defined in: keyboard-shortcuts.ts:55
#### Parameters
##### event
`TKeyboardEvent`
#### Returns
`boolean`
***
### keys
> **keys**: `ReadonlyArray`\<`string`\>
Defined in: keyboard-shortcuts.ts:56
# KeyboardShortcutDefinition
> **KeyboardShortcutDefinition** = `object`
Defined in: keyboard-shortcuts.ts:33
Definition of a keyboard shortcut with platform-specific keyboard event
definitions.
`default` keyboard event definitions are required while the `apple`
keyboard event definitions are optional.
## Example
```typescript
const boldShortcut: KeyboardShortcutDefinition = {
default: [{
key: 'B',
alt: false,
ctrl: true,
meta: false,
shift: false,
}],
apple: [{
key: 'B',
alt: false,
ctrl: false,
meta: true,
shift: false,
}],
}
```
## Properties
### apple?
> `optional` **apple**: `ReadonlyArray`\<[`KeyboardEventDefinition`](/api/keyboard-shortcuts/type-aliases/keyboardeventdefinition/)\>
Defined in: keyboard-shortcuts.ts:35
***
### default
> **default**: `ReadonlyArray`\<[`KeyboardEventDefinition`](/api/keyboard-shortcuts/type-aliases/keyboardeventdefinition/)\>
Defined in: keyboard-shortcuts.ts:34
# blockquote
> `const` **blockquote**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:444
# bold
> `const` **bold**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:6
# code
> `const` **code**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:54
# h1
> `const` **h1**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:192
# h2
> `const` **h2**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:234
# h3
> `const` **h3**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:276
# h4
> `const` **h4**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:318
# h5
> `const` **h5**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:360
# h6
> `const` **h6**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:402
# italic
> `const` **italic**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:30
# link
> `const` **link**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:126
# normal
> `const` **normal**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:150
# redo
> `const` **redo**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:483
# strikeThrough
> `const` **strikeThrough**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:102
# underline
> `const` **underline**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:78
# undo
> `const` **undo**: [`KeyboardShortcut`](/api/keyboard-shortcuts/type-aliases/keyboardshortcut/)\<`Pick`\<`KeyboardEvent`, `"key"` \| `"code"` \| `"altKey"` \| `"ctrlKey"` \| `"metaKey"` \| `"shiftKey"`\>\>
Defined in: common-shortcuts.ts:459
# BehaviorPlugin
> **BehaviorPlugin**(`props`): `null`
Defined in: plugin.behavior.tsx:15
Plugin component that registers a list of `Behavior`s with the editor.
Stabilize the `behaviors` array (a module-level constant or `useMemo`)
to avoid a full unregister/re-register cycle on every parent render: a
new array reference per render triggers the registration effect to
re-run.
## Parameters
### props
#### behaviors
`Behavior`[]
## Returns
`null`
# EventListenerPlugin
> **EventListenerPlugin**(`props`): `null`
Defined in: plugin.event-listener.tsx:51
Listen for events emitted by the editor. Must be used inside `EditorProvider`. Events available include:
- 'blurred'
- 'editable'
- 'focused'
- 'invalid value'
- 'mutation'
- 'patch'
- 'read only'
- 'ready'
- 'selection'
- 'value changed'
## Parameters
### props
#### on
(`event`) => `void`
## Returns
`null`
## Examples
Listen and log events.
```tsx
import {EditorProvider} from '@portabletext/editor'
import {EventListenerPlugin} from '@portabletext/editor/plugins'
function MyComponent() {
return (
{
console.log(event)
}
} />
{ ... }
)
}
```
Handle events when there is a mutation.
```tsx
{
if (event.type === 'mutation') {
console.log('Value changed:', event.snapshot)
}
}}
/>
```
# NodePlugin
> **NodePlugin**(`props`): `null`
Defined in: plugin.node.tsx:17
Plugin component that registers a list of nodes (containers, text
blocks, spans, block objects, inline objects, decorators, annotations)
with the editor. Each node is the result of a `defineX` factory.
Stabilize the `nodes` array (a module-level constant or `useMemo`)
to avoid a full unregister/re-register cycle on every parent
render: a new array reference per render triggers the registration
effect to re-run.
## Parameters
### props
#### nodes
`RegistrableNode`[]
## Returns
`null`
# @portabletext/editor
## Variables
- [EditorRefPlugin](/api/plugins/variables/editorrefplugin/)
## Functions
- [BehaviorPlugin](/api/plugins/functions/behaviorplugin/)
- [NodePlugin](/api/plugins/functions/nodeplugin/)
## Components
- [EventListenerPlugin](/api/plugins/functions/eventlistenerplugin/)
# EditorRefPlugin
> `const` **EditorRefPlugin**: `ForwardRefExoticComponent`\<`RefAttributes`\<`Editor` \| `null`\>\>
Defined in: plugin.editor-ref.tsx:8
# compareApplicableSchema
> **compareApplicableSchema**(`a`, `b`): `boolean`
Defined in: selector.get-applicable-schema.ts:111
Structural comparator for [ApplicableSchema](/api/selectors/type-aliases/applicableschema/) values. Two results
compare equal when every category contains the same names (set equality).
Pass as the `compare` argument to `useEditorSelector` to keep React
subscriptions stable.
## Parameters
### a
[`ApplicableSchema`](/api/selectors/type-aliases/applicableschema/)
### b
[`ApplicableSchema`](/api/selectors/type-aliases/applicableschema/)
## Returns
`boolean`
# isActiveAnnotation
> **isActiveAnnotation**(`annotation`, `options?`): `EditorSelector`\<`boolean`\>
Defined in: selector.is-active-annotation.ts:13
Check whether an annotation is active in the given `snapshot`.
## Parameters
### annotation
`string`
### options?
#### mode?
`"partial"` \| `"full"`
Choose whether the annotation has to cover the entire selection
(`'full'`) or whether the selection covering at least one character
of the annotation suffices (`'partial'`). With a collapsed
selection the modes agree: the annotation is active when the caret
sits inside it, not at its edges.
Defaults to `'full'`
## Returns
`EditorSelector`\<`boolean`\>
# isActiveDecorator
> **isActiveDecorator**(`decorator`): `EditorSelector`\<`boolean`\>
Defined in: selector.is-active-decorator.ts:10
## Parameters
### decorator
`string`
## Returns
`EditorSelector`\<`boolean`\>
# isActiveListItem
> **isActiveListItem**(`listItem`): `EditorSelector`\<`boolean`\>
Defined in: selector.is-active-list-item.ts:7
## Parameters
### listItem
`string`
## Returns
`EditorSelector`\<`boolean`\>
# isActiveStyle
> **isActiveStyle**(`style`): `EditorSelector`\<`boolean`\>
Defined in: selector.is-active-style.ts:7
## Parameters
### style
`string`
## Returns
`EditorSelector`\<`boolean`\>
# isAtTheEndOfBlock
> **isAtTheEndOfBlock**(`block`): `EditorSelector`\<`boolean`\>
Defined in: selector.is-at-the-end-of-block.ts:11
## Parameters
### block
#### node
`PortableTextBlock`
#### path
`Path`
## Returns
`EditorSelector`\<`boolean`\>
# isAtTheStartOfBlock
> **isAtTheStartOfBlock**(`block`): `EditorSelector`\<`boolean`\>
Defined in: selector.is-at-the-start-of-block.ts:11
## Parameters
### block
#### node
`PortableTextBlock`
#### path
`Path`
## Returns
`EditorSelector`\<`boolean`\>
# isOverlappingSelection
> **isOverlappingSelection**(`selection`): `EditorSelector`\<`boolean`\>
Defined in: selector.is-overlapping-selection.ts:15
Returns true if the supplied selection shares at least one point with the
editor's current selection. Resolves at any container depth.
Two selections that touch at a single endpoint share that point and are
considered overlapping.
## Parameters
### selection
`EditorSelection`
## Returns
`EditorSelector`\<`boolean`\>
# isPointAfterSelection
> **isPointAfterSelection**(`point`): `EditorSelector`\<`boolean`\>
Defined in: selector.is-point-after-selection.ts:9
## Parameters
### point
`EditorSelectionPoint`
## Returns
`EditorSelector`\<`boolean`\>
# isPointBeforeSelection
> **isPointBeforeSelection**(`point`): `EditorSelector`\<`boolean`\>
Defined in: selector.is-point-before-selection.ts:9
## Parameters
### point
`EditorSelectionPoint`
## Returns
`EditorSelector`\<`boolean`\>
# @portabletext/editor
## Type Aliases
- [ApplicableSchema](/api/selectors/type-aliases/applicableschema/)
- [MarkState](/api/selectors/type-aliases/markstate/)
## Variables
- [getActiveAnnotations](/api/selectors/variables/getactiveannotations/)
- [getActiveListItem](/api/selectors/variables/getactivelistitem/)
- [getActiveStyle](/api/selectors/variables/getactivestyle/)
- [getAnchorBlock](/api/selectors/variables/getanchorblock/)
- [getAnchorChild](/api/selectors/variables/getanchorchild/)
- [getAnchorSpan](/api/selectors/variables/getanchorspan/)
- [getAnchorTextBlock](/api/selectors/variables/getanchortextblock/)
- [getApplicableSchema](/api/selectors/variables/getapplicableschema/)
- [getBlockOffsets](/api/selectors/variables/getblockoffsets/)
- [getBlockTextAfter](/api/selectors/variables/getblocktextafter/)
- [getBlockTextBefore](/api/selectors/variables/getblocktextbefore/)
- [getCaretWordSelection](/api/selectors/variables/getcaretwordselection/)
- [getFirstBlock](/api/selectors/variables/getfirstblock/)
- [getFocusBlock](/api/selectors/variables/getfocusblock/)
- [getFocusBlockObject](/api/selectors/variables/getfocusblockobject/)
- [getFocusChild](/api/selectors/variables/getfocuschild/)
- [getFocusInlineObject](/api/selectors/variables/getfocusinlineobject/)
- [getFocusListBlock](/api/selectors/variables/getfocuslistblock/)
- [getFocusSpan](/api/selectors/variables/getfocusspan/)
- [getFocusTextBlock](/api/selectors/variables/getfocustextblock/)
- [getFragment](/api/selectors/variables/getfragment/)
- [getLastBlock](/api/selectors/variables/getlastblock/)
- [getMarkState](/api/selectors/variables/getmarkstate/)
- [getNextBlock](/api/selectors/variables/getnextblock/)
- [getNextInlineObject](/api/selectors/variables/getnextinlineobject/)
- [getNextInlineObjects](/api/selectors/variables/getnextinlineobjects/)
- [getNextSpan](/api/selectors/variables/getnextspan/)
- [getPreviousBlock](/api/selectors/variables/getpreviousblock/)
- [getPreviousInlineObject](/api/selectors/variables/getpreviousinlineobject/)
- [getPreviousInlineObjects](/api/selectors/variables/getpreviousinlineobjects/)
- [getPreviousSpan](/api/selectors/variables/getpreviousspan/)
- [getSelectedBlocks](/api/selectors/variables/getselectedblocks/)
- [getSelectedSpans](/api/selectors/variables/getselectedspans/)
- [getSelectedTextBlocks](/api/selectors/variables/getselectedtextblocks/)
- [getSelectedValue](/api/selectors/variables/getselectedvalue/)
- [getSelection](/api/selectors/variables/getselection/)
- [getSelectionEndBlock](/api/selectors/variables/getselectionendblock/)
- [getSelectionEndChild](/api/selectors/variables/getselectionendchild/)
- [getSelectionEndPoint](/api/selectors/variables/getselectionendpoint/)
- [getSelectionStartBlock](/api/selectors/variables/getselectionstartblock/)
- [getSelectionStartChild](/api/selectors/variables/getselectionstartchild/)
- [getSelectionStartPoint](/api/selectors/variables/getselectionstartpoint/)
- [getSelectionText](/api/selectors/variables/getselectiontext/)
- [getValue](/api/selectors/variables/getvalue/)
- [isSelectingEntireBlocks](/api/selectors/variables/isselectingentireblocks/)
- [isSelectionCollapsed](/api/selectors/variables/isselectioncollapsed/)
- [isSelectionExpanded](/api/selectors/variables/isselectionexpanded/)
## Functions
- [compareApplicableSchema](/api/selectors/functions/compareapplicableschema/)
- [isActiveAnnotation](/api/selectors/functions/isactiveannotation/)
- [isActiveDecorator](/api/selectors/functions/isactivedecorator/)
- [isActiveListItem](/api/selectors/functions/isactivelistitem/)
- [isActiveStyle](/api/selectors/functions/isactivestyle/)
- [isAtTheEndOfBlock](/api/selectors/functions/isattheendofblock/)
- [isAtTheStartOfBlock](/api/selectors/functions/isatthestartofblock/)
- [isOverlappingSelection](/api/selectors/functions/isoverlappingselection/)
- [isPointAfterSelection](/api/selectors/functions/ispointafterselection/)
- [isPointBeforeSelection](/api/selectors/functions/ispointbeforeselection/)
# ApplicableSchema
> **ApplicableSchema** = `object`
Defined in: selector.get-applicable-schema.ts:12
The set of schema member names applicable at the current selection,
grouped by category.
## Properties
### annotations
> **annotations**: `ReadonlySet`\<`string`\>
Defined in: selector.get-applicable-schema.ts:14
***
### blockObjects
> **blockObjects**: `ReadonlySet`\<`string`\>
Defined in: selector.get-applicable-schema.ts:17
***
### decorators
> **decorators**: `ReadonlySet`\<`string`\>
Defined in: selector.get-applicable-schema.ts:13
***
### inlineObjects
> **inlineObjects**: `ReadonlySet`\<`string`\>
Defined in: selector.get-applicable-schema.ts:18
***
### lists
> **lists**: `ReadonlySet`\<`string`\>
Defined in: selector.get-applicable-schema.ts:15
***
### styles
> **styles**: `ReadonlySet`\<`string`\>
Defined in: selector.get-applicable-schema.ts:16
# MarkState
> **MarkState** = \{ `marks`: `string`[]; `state`: `"unchanged"`; \} \| \{ `marks`: `string`[]; `previousMarks`: `string`[]; `state`: `"changed"`; \}
Defined in: selector.get-mark-state.ts:16
# getActiveAnnotations
> `const` **getActiveAnnotations**: `EditorSelector`\<`PortableTextObject`[]\>
Defined in: selector.get-active-annotations.ts:10
# getActiveListItem
> `const` **getActiveListItem**: `EditorSelector`\<`PortableTextListBlock`\[`"listItem"`\] \| `undefined`\>
Defined in: selector.get-active-list-item.ts:9
# getActiveStyle
> `const` **getActiveStyle**: `EditorSelector`\<`PortableTextTextBlock`\[`"style"`\]\>
Defined in: selector.get-active-style.ts:9
# getAnchorBlock
> `const` **getAnchorBlock**: `EditorSelector`\<\{ `node`: `PortableTextBlock`; `path`: `BlockPath`; \} \| `undefined`\>
Defined in: selector.get-anchor-block.ts:11
Returns the block containing the anchor selection, resolved at any depth.
# getAnchorChild
> `const` **getAnchorChild**: `EditorSelector`\<\{ `node`: `PortableTextObject` \| `PortableTextSpan`; `path`: `ChildPath`; \} \| `undefined`\>
Defined in: selector.get-anchor-child.ts:12
Returns the child (span or inline object) containing the anchor selection,
resolved at any depth.
# getAnchorSpan
> `const` **getAnchorSpan**: `EditorSelector`\<\{ `node`: `PortableTextSpan`; `path`: `ChildPath`; \} \| `undefined`\>
Defined in: selector.get-anchor-span.ts:11
Returns the span containing the anchor selection, resolved at any depth.
# getAnchorTextBlock
> `const` **getAnchorTextBlock**: `EditorSelector`\<\{ `node`: `PortableTextTextBlock`; `path`: `BlockPath`; \} \| `undefined`\>
Defined in: selector.get-anchor-text-block.ts:12
Returns the text block containing the anchor selection, resolved at any
depth.
# getApplicableSchema
> `const` **getApplicableSchema**: `EditorSelector`\<[`ApplicableSchema`](/api/selectors/type-aliases/applicableschema/)\>
Defined in: selector.get-applicable-schema.ts:56
Resolve which schema members are applicable at the current selection. For
each named category (decorators, annotations, lists, styles, block objects,
inline objects) returns the set of names that the editor allows at the
current selection.
Categories split by what they apply to:
Text-only (decorators, annotations, lists, styles): require text-block
content in the selection. A name is applicable when at least one text
block the range covers declares it (union). The underlying operations
apply per-block, validating each block's sub-schema and skipping blocks
that don't declare the type, so the result reflects "will this produce
any effect?" semantics. Selection on a void block, or no selection,
returns empty sets.
Insertion (blockObjects, inlineObjects): the things consumers might
insert AT the current selection. The focus block's sub-schema applies
even when the selection is on a void block (the question "what can I
insert here?" still has an answer). No selection returns empty sets.
Useful for gating toolbar buttons, slash-command items, command palettes,
keyboard-shortcut hints and other selection-aware UIs.
Pair with `getUnionSchema` (from `@portabletext/editor/traversal`) to render a static toolbar whose
buttons stay stable across selection moves while gating their enabled
state on whether the corresponding name is in the relevant set.
Note for React consumers: the returned object is a fresh value on every
call, so subscribing via `useEditorSelector` requires a structural
compare to avoid re-rendering on every editor tick. Use
[compareApplicableSchema](/api/selectors/functions/compareapplicableschema/) as the third argument.
# getBlockOffsets
> `const` **getBlockOffsets**: `EditorSelector`\<\{ `end`: `BlockOffset`; `start`: `BlockOffset`; \} \| `undefined`\>
Defined in: selector.get-block-offsets.ts:10
# getBlockTextAfter
> `const` **getBlockTextAfter**: `EditorSelector`\<`string`\>
Defined in: selector.get-text-after.ts:10
# getBlockTextBefore
> `const` **getBlockTextBefore**: `EditorSelector`\<`string`\>
Defined in: selector.get-text-before.ts:10
# getCaretWordSelection
> `const` **getCaretWordSelection**: `EditorSelector`\<`EditorSelection`\>
Defined in: selector.get-caret-word-selection.ts:23
Returns the selection of the of the word the caret is placed in.
Note: Only returns a word selection if the current selection is collapsed
# getFirstBlock
> `const` **getFirstBlock**: `EditorSelector`\<\{ `node`: `PortableTextBlock`; `path`: `BlockPath`; \} \| `undefined`\>
Defined in: selector.get-first-block.ts:19
Returns the first block at the current container scope.
When the focus is inside an editable container (e.g. a code block's line),
this returns the first block within that container (the first line). When
the focus is at root, or there is no selection, this returns the first
block in the document.
# getFocusBlock
> `const` **getFocusBlock**: `EditorSelector`\<\{ `node`: `PortableTextBlock`; `path`: `BlockPath`; \} \| `undefined`\>
Defined in: selector.get-focus-block.ts:15
Returns the block containing the focus selection, resolved at any depth.
When the focus is inside an editable container (e.g. a code block's line),
this returns the innermost block ancestor (the line), not the outer
container. When the focus is at root, behavior is unchanged.
# getFocusBlockObject
> `const` **getFocusBlockObject**: `EditorSelector`\<\{ `node`: `PortableTextObject`; `path`: `BlockPath`; \} \| `undefined`\>
Defined in: selector.get-focus-block-object.ts:17
Returns the void block object containing the focus selection, resolved at
any depth.
Excludes text blocks and editable containers (which have their own children
and are not "void"). When the focus is at root, behavior is unchanged.
# getFocusChild
> `const` **getFocusChild**: `EditorSelector`\<\{ `node`: `PortableTextObject` \| `PortableTextSpan`; `path`: `ChildPath`; \} \| `undefined`\>
Defined in: selector.get-focus-child.ts:12
Returns the child (span or inline object) containing the focus selection,
resolved at any depth.
# getFocusInlineObject
> `const` **getFocusInlineObject**: `EditorSelector`\<\{ `node`: `PortableTextObject`; `path`: `ChildPath`; \} \| `undefined`\>
Defined in: selector.get-focus-inline-object.ts:13
Returns the inline object containing the focus selection, resolved at any
depth.
# getFocusListBlock
> `const` **getFocusListBlock**: `EditorSelector`\<\{ `node`: `PortableTextListBlock`; `path`: `BlockPath`; \} \| `undefined`\>
Defined in: selector.get-focus-list-block.ts:13
Returns the list block containing the focus selection, resolved at any
depth.
# getFocusSpan
> `const` **getFocusSpan**: `EditorSelector`\<\{ `node`: `PortableTextSpan`; `path`: `ChildPath`; \} \| `undefined`\>
Defined in: selector.get-focus-span.ts:11
Returns the span containing the focus selection, resolved at any depth.
# getFocusTextBlock
> `const` **getFocusTextBlock**: `EditorSelector`\<\{ `node`: `PortableTextTextBlock`; `path`: `BlockPath`; \} \| `undefined`\>
Defined in: selector.get-focus-text-block.ts:15
Returns the text block containing the focus selection, resolved at any depth.
When the focus is inside an editable container (e.g. a code block's line),
this returns the innermost text block ancestor (the line), not the outer
container. When the focus is at root, behavior is unchanged.
# getFragment
> `const` **getFragment**: `EditorSelector`\<`object`[]\>
Defined in: selector.get-fragment.ts:37
Returns the smallest top-level-valid fragment of the editor's value
that covers the current selection.
Starts from [getSelectedValue](/api/selectors/variables/getselectedvalue/)'s envelope and unwraps it toward
the selection's lowest common ancestor, stopping at the deepest level
whose siblings are all root-accepted types. Intermediate single-child
containers (a single row inside a table, a single cell inside a row)
are walked through to look for a deeper unwrap target; an intermediate
level with multiple siblings (the lowest common ancestor across two
cells in one row) ends the walk and the last root-valid wrapping is
returned.
A selection whose endpoints terminate at the root level (collapsed at
a root-level node, or expanded across root siblings without descending
into them) is treated as the user pointing AT the named node(s) rather
than INTO them; the envelope is returned as-is and the unwrap walk is
skipped. This is how a chrome drag carries the container itself rather
than its unwrapped content.
Backs every registered clipboard converter, `editor.getFragment()`
(which projects to blocks only), and the drag preview pipeline (which
uses the paths to find DOM nodes). Exposed for custom converters and
any consumer that needs the clipboard-shaped view of the current
selection without redundant ancestor envelopes.
# getLastBlock
> `const` **getLastBlock**: `EditorSelector`\<\{ `node`: `PortableTextBlock`; `path`: `BlockPath`; \} \| `undefined`\>
Defined in: selector.get-last-block.ts:19
Returns the last block at the current container scope.
When the focus is inside an editable container (e.g. a code block's line),
this returns the last block within that container (the last line). When
the focus is at root, or there is no selection, this returns the last
block in the document.
# getMarkState
> `const` **getMarkState**: `EditorSelector`\<[`MarkState`](/api/selectors/type-aliases/markstate/) \| `undefined`\>
Defined in: selector.get-mark-state.ts:32
Given that text is inserted at the current position, what marks should
be applied?
# getNextBlock
> `const` **getNextBlock**: `EditorSelector`\<\{ `node`: `PortableTextBlock`; `path`: `BlockPath`; \} \| `undefined`\>
Defined in: selector.get-next-block.ts:17
Returns the block after the selection's end block within the same
container scope, if any.
Siblings are resolved within the enclosing container (or the document root
if the selection is at root level). Never crosses container boundaries.
# getNextInlineObject
> `const` **getNextInlineObject**: `EditorSelector`\<\{ `node`: `PortableTextObject`; `path`: `ChildPath`; \} \| `undefined`\>
Defined in: selector.get-next-inline-object.ts:14
Returns the inline object after the selection end within the same text
block, resolved at any depth.
# getNextInlineObjects
> `const` **getNextInlineObjects**: `EditorSelector`\<`object`[]\>
Defined in: selector.get-next-inline-objects.ts:16
Returns all inline objects after the selection end within the same text
block, resolved at any depth.
# getNextSpan
> `const` **getNextSpan**: `EditorSelector`\<\{ `node`: `PortableTextSpan`; `path`: `Path`; \} \| `undefined`\>
Defined in: selector.get-next-span.ts:13
Returns the span after the selection end within the same text block,
resolved at any depth.
# getPreviousBlock
> `const` **getPreviousBlock**: `EditorSelector`\<\{ `node`: `PortableTextBlock`; `path`: `BlockPath`; \} \| `undefined`\>
Defined in: selector.get-previous-block.ts:17
Returns the block before the selection's start block within the same
container scope, if any.
Siblings are resolved within the enclosing container (or the document root
if the selection is at root level). Never crosses container boundaries.
# getPreviousInlineObject
> `const` **getPreviousInlineObject**: `EditorSelector`\<\{ `node`: `PortableTextObject`; `path`: `ChildPath`; \} \| `undefined`\>
Defined in: selector.get-previous-inline-object.ts:14
Returns the inline object before the selection start within the same text
block, resolved at any depth.
# getPreviousInlineObjects
> `const` **getPreviousInlineObjects**: `EditorSelector`\<`object`[]\>
Defined in: selector.get-previous-inline-objects.ts:16
Returns all inline objects before the selection start within the same text
block, resolved at any depth.
# getPreviousSpan
> `const` **getPreviousSpan**: `EditorSelector`\<\{ `node`: `PortableTextSpan`; `path`: `Path`; \} \| `undefined`\>
Defined in: selector.get-previous-span.ts:13
Returns the span before the selection start within the same text block,
resolved at any depth.
# getSelectedBlocks
> `const` **getSelectedBlocks**: `EditorSelector`\<`object`[]\>
Defined in: selector.get-selected-blocks.ts:23
Returns the root-level blocks the selection covers.
Only looks at direct children of the editor. If the selection is inside
an editable container, the container itself is returned - not its inner
blocks. Containers are preserved whole.
Use for block-level operations like `move.block up/down` and
drag-and-drop. For "selection as portable text" use `getSelectedValue`;
for "text blocks at any depth" use `getSelectedTextBlocks`.
# getSelectedSpans
> `const` **getSelectedSpans**: `EditorSelector`\<`object`[]\>
Defined in: selector.get-selected-spans.ts:11
Returns the spans touched by the selection, resolved at any depth.
# getSelectedTextBlocks
> `const` **getSelectedTextBlocks**: `EditorSelector`\<`object`[]\>
Defined in: selector.get-selected-text-blocks.ts:18
Returns the text blocks touched by the selection, resolved at any depth.
Walks the tree between the selection endpoints and returns every text
block found, regardless of container nesting. For toolbar state and
anywhere that needs "text blocks with text in the selection".
# getSelectedValue
> `const` **getSelectedValue**: `EditorSelector`\<`PortableTextBlock`[]\>
Defined in: selector.get-selected-value.ts:39
Returns the portion of the document's value covered by the selection,
resolved at any depth.
Containers fully inside the selection are preserved verbatim. Containers
on the selection boundary are recursed into so only the selected portion
of their content is kept. Text blocks on the boundary are span-sliced.
The result preserves the full ancestor envelope around the selection. For
the clipboard-shaped view that unwraps the envelope toward the selection's
lowest common ancestor, see [getFragment](/api/selectors/variables/getfragment/).
# getSelection
> `const` **getSelection**: `EditorSelector`\<`EditorSelection`\>
Defined in: selector.get-selection.ts:7
# getSelectionEndBlock
> `const` **getSelectionEndBlock**: `EditorSelector`\<\{ `node`: `PortableTextBlock`; `path`: `BlockPath`; \} \| `undefined`\>
Defined in: selector.get-selection-end-block.ts:13
Returns the block containing the selection's end point, resolved at any
depth.
# getSelectionEndChild
> `const` **getSelectionEndChild**: `EditorSelector`\<\{ `node`: `PortableTextSpan` \| `PortableTextObject`; `path`: `ChildPath`; \} \| `undefined`\>
Defined in: selector.get-selection-end-child.ts:13
Returns the child containing the selection's end point, resolved at any
depth.
# getSelectionEndPoint
> `const` **getSelectionEndPoint**: `EditorSelector`\<`EditorSelectionPoint` \| `undefined`\>
Defined in: selector.get-selection-end-point.ts:7
# getSelectionStartBlock
> `const` **getSelectionStartBlock**: `EditorSelector`\<\{ `node`: `PortableTextBlock`; `path`: `BlockPath`; \} \| `undefined`\>
Defined in: selector.get-selection-start-block.ts:13
Returns the block containing the selection's start point, resolved at any
depth.
# getSelectionStartChild
> `const` **getSelectionStartChild**: `EditorSelector`\<\{ `node`: `PortableTextSpan` \| `PortableTextObject`; `path`: `ChildPath`; \} \| `undefined`\>
Defined in: selector.get-selection-start-child.ts:13
Returns the child containing the selection's start point, resolved at any
depth.
# getSelectionStartPoint
> `const` **getSelectionStartPoint**: `EditorSelector`\<`EditorSelectionPoint` \| `undefined`\>
Defined in: selector.get-selection-start-point.ts:7
# getSelectionText
> `const` **getSelectionText**: `EditorSelector`\<`string`\>
Defined in: selector.get-selection-text.ts:12
# getValue
> `const` **getValue**: `EditorSelector`\<`PortableTextBlock`[]\>
Defined in: selector.get-value.ts:7
# isSelectingEntireBlocks
> `const` **isSelectingEntireBlocks**: `EditorSelector`\<`boolean`\>
Defined in: selector.is-selecting-entire-blocks.ts:11
# isSelectionCollapsed
> `const` **isSelectionCollapsed**: `EditorSelector`\<`boolean`\>
Defined in: selector.is-selection-collapsed.ts:7
# isSelectionExpanded
> `const` **isSelectionExpanded**: `EditorSelector`\<`boolean`\>
Defined in: selector.is-selection-expanded.ts:7
# useAnnotationButton
> **useAnnotationButton**(`props`): [`AnnotationButton`](/api/toolbar/type-aliases/annotationbutton/)
Defined in: toolbar/src/use-annotation-button.ts:301
Manages the state, keyboard shortcut and available events for an annotation
button.
Note: This hook assumes that the button triggers a dialog for inputting
the annotation value.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### props
#### schemaType
[`ToolbarAnnotationSchemaType`](/api/toolbar/type-aliases/toolbarannotationschematype/)
## Returns
[`AnnotationButton`](/api/toolbar/type-aliases/annotationbutton/)
# useAnnotationPopover
> **useAnnotationPopover**(`props`): [`AnnotationPopover`](/api/toolbar/type-aliases/annotationpopover/)
Defined in: toolbar/src/use-annotation-popover.ts:280
Manages the state and available events for an annotation popover.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### props
#### schemaTypes
readonly [`ToolbarAnnotationSchemaType`](/api/toolbar/type-aliases/toolbarannotationschematype/)[]
## Returns
[`AnnotationPopover`](/api/toolbar/type-aliases/annotationpopover/)
# useApplicableSchema
> **useApplicableSchema**(): [`ApplicableSchema`](/api/toolbar/type-aliases/applicableschema/)
Defined in: toolbar/src/use-applicable-schema.ts:21
React hook that subscribes to getApplicableSchema for the active
editor and returns a stable reference across editor ticks while the
applicable set is unchanged.
Pair with [useToolbarSchema](/api/toolbar/functions/usetoolbarschema/) to render a static toolbar whose
buttons stay stable across selection moves and gate their enabled state
on whether the corresponding name is in the relevant set.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Returns
[`ApplicableSchema`](/api/toolbar/type-aliases/applicableschema/)
# useBlockObjectButton
> **useBlockObjectButton**(`props`): [`BlockObjectButton`](/api/toolbar/type-aliases/blockobjectbutton/)
Defined in: toolbar/src/use-block-object-button.ts:172
Manages the state, keyboard shortcut and available events for a block
object button.
Note: This hook assumes that the button triggers a dialog for inputting
the block object value.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### props
#### schemaType
[`ToolbarBlockObjectSchemaType`](/api/toolbar/type-aliases/toolbarblockobjectschematype/)
## Returns
[`BlockObjectButton`](/api/toolbar/type-aliases/blockobjectbutton/)
# useBlockObjectPopover
> **useBlockObjectPopover**(`props`): [`BlockObjectPopover`](/api/toolbar/type-aliases/blockobjectpopover/)
Defined in: toolbar/src/use-block-object-popover.ts:268
Manages the state and available events for a block object popover.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### props
#### schemaTypes
readonly [`ToolbarBlockObjectSchemaType`](/api/toolbar/type-aliases/toolbarblockobjectschematype/)[]
## Returns
[`BlockObjectPopover`](/api/toolbar/type-aliases/blockobjectpopover/)
# useDecoratorButton
> **useDecoratorButton**(`props`): [`DecoratorButton`](/api/toolbar/type-aliases/decoratorbutton/)
Defined in: toolbar/src/use-decorator-button.ts:180
Manages the state, keyboard shortcuts and available events for a decorator
button and sets up mutually exclusive decorator behaviors.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### props
#### schemaType
[`ToolbarDecoratorSchemaType`](/api/toolbar/type-aliases/toolbardecoratorschematype/)
## Returns
[`DecoratorButton`](/api/toolbar/type-aliases/decoratorbutton/)
# useHistoryButtons
> **useHistoryButtons**(): [`HistoryButtons`](/api/toolbar/type-aliases/historybuttons/)
Defined in: toolbar/src/use-history-buttons.ts:83
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Returns
[`HistoryButtons`](/api/toolbar/type-aliases/historybuttons/)
# useInlineObjectButton
> **useInlineObjectButton**(`props`): [`InlineObjectButton`](/api/toolbar/type-aliases/inlineobjectbutton/)
Defined in: toolbar/src/use-inline-object-button.ts:166
Manages the state, keyboard shortcut and available events for an inline
object button.
Note: This hook assumes that the button triggers a dialog for inputting
the inline object value.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### props
#### schemaType
[`ToolbarInlineObjectSchemaType`](/api/toolbar/type-aliases/toolbarinlineobjectschematype/)
## Returns
[`InlineObjectButton`](/api/toolbar/type-aliases/inlineobjectbutton/)
# useInlineObjectPopover
> **useInlineObjectPopover**(`props`): [`InlineObjectPopover`](/api/toolbar/type-aliases/inlineobjectpopover/)
Defined in: toolbar/src/use-inline-object-popover.ts:268
Manages the state and available events for an inline object popover.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### props
#### schemaTypes
readonly [`ToolbarInlineObjectSchemaType`](/api/toolbar/type-aliases/toolbarinlineobjectschematype/)[]
## Returns
[`InlineObjectPopover`](/api/toolbar/type-aliases/inlineobjectpopover/)
# useListButton
> **useListButton**(`props`): [`ListButton`](/api/toolbar/type-aliases/listbutton/)
Defined in: toolbar/src/use-list-button.ts:173
Manages the state, keyboard shortcuts and available events for a list button.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### props
#### schemaType
[`ToolbarListSchemaType`](/api/toolbar/type-aliases/toolbarlistschematype/)
## Returns
[`ListButton`](/api/toolbar/type-aliases/listbutton/)
# useStyleSelector
> **useStyleSelector**(`props`): [`StyleSelector`](/api/toolbar/type-aliases/styleselector/)
Defined in: toolbar/src/use-style-selector.ts:138
Manages the state, keyboard shortcuts and available events for a style
selector.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### props
#### schemaTypes
readonly [`ToolbarStyleSchemaType`](/api/toolbar/type-aliases/toolbarstyleschematype/)[]
## Returns
[`StyleSelector`](/api/toolbar/type-aliases/styleselector/)
# useToolbarSchema
> **useToolbarSchema**(`props`): [`ToolbarSchema`](/api/toolbar/type-aliases/toolbarschema/)
Defined in: toolbar/src/use-toolbar-schema.ts:74
Resolve the editor's full toolbar schema. Returns the union of every
decorator, annotation, list, style, block object and inline object declared
anywhere in the editor's schema graph that is reachable from a position
where text is edited - the root schema merged with the sub-schema of every
registered container whose field accepts text blocks. Useful for rendering
a static toolbar whose buttons stay stable across selection moves.
Re-renders only when the schema graph or the extension callbacks change.
Pair with [useApplicableSchema](/api/toolbar/functions/useapplicableschema/) to determine which entries are
applicable at the current selection (which buttons should be enabled vs.
disabled).
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### props
#### extendAnnotation?
[`ExtendAnnotationSchemaType`](/api/toolbar/type-aliases/extendannotationschematype/)
#### extendBlockObject?
[`ExtendBlockObjectSchemaType`](/api/toolbar/type-aliases/extendblockobjectschematype/)
#### extendDecorator?
[`ExtendDecoratorSchemaType`](/api/toolbar/type-aliases/extenddecoratorschematype/)
#### extendInlineObject?
[`ExtendInlineObjectSchemaType`](/api/toolbar/type-aliases/extendinlineobjectschematype/)
#### extendList?
[`ExtendListSchemaType`](/api/toolbar/type-aliases/extendlistschematype/)
#### extendStyle?
[`ExtendStyleSchemaType`](/api/toolbar/type-aliases/extendstyleschematype/)
## Returns
[`ToolbarSchema`](/api/toolbar/type-aliases/toolbarschema/)
# @portabletext/toolbar
## Type Aliases
- [AnnotationButton](/api/toolbar/type-aliases/annotationbutton/)
- [AnnotationButtonEvent](/api/toolbar/type-aliases/annotationbuttonevent/)
- [AnnotationPopover](/api/toolbar/type-aliases/annotationpopover/)
- [AnnotationPopoverEvent](/api/toolbar/type-aliases/annotationpopoverevent/)
- [ApplicableSchema](/api/toolbar/type-aliases/applicableschema/)
- [BlockObjectButton](/api/toolbar/type-aliases/blockobjectbutton/)
- [BlockObjectButtonEvent](/api/toolbar/type-aliases/blockobjectbuttonevent/)
- [BlockObjectPopover](/api/toolbar/type-aliases/blockobjectpopover/)
- [BlockObjectPopoverEvent](/api/toolbar/type-aliases/blockobjectpopoverevent/)
- [DecoratorButton](/api/toolbar/type-aliases/decoratorbutton/)
- [DecoratorButtonEvent](/api/toolbar/type-aliases/decoratorbuttonevent/)
- [ExtendAnnotationSchemaType](/api/toolbar/type-aliases/extendannotationschematype/)
- [ExtendBlockObjectSchemaType](/api/toolbar/type-aliases/extendblockobjectschematype/)
- [ExtendDecoratorSchemaType](/api/toolbar/type-aliases/extenddecoratorschematype/)
- [ExtendInlineObjectSchemaType](/api/toolbar/type-aliases/extendinlineobjectschematype/)
- [ExtendListSchemaType](/api/toolbar/type-aliases/extendlistschematype/)
- [ExtendStyleSchemaType](/api/toolbar/type-aliases/extendstyleschematype/)
- [HistoryButtons](/api/toolbar/type-aliases/historybuttons/)
- [HistoryButtonsEvent](/api/toolbar/type-aliases/historybuttonsevent/)
- [InlineObjectButton](/api/toolbar/type-aliases/inlineobjectbutton/)
- [InlineObjectButtonEvent](/api/toolbar/type-aliases/inlineobjectbuttonevent/)
- [InlineObjectPopover](/api/toolbar/type-aliases/inlineobjectpopover/)
- [InlineObjectPopoverEvent](/api/toolbar/type-aliases/inlineobjectpopoverevent/)
- [ListButton](/api/toolbar/type-aliases/listbutton/)
- [ListButtonEvent](/api/toolbar/type-aliases/listbuttonevent/)
- [StyleSelector](/api/toolbar/type-aliases/styleselector/)
- [StyleSelectorEvent](/api/toolbar/type-aliases/styleselectorevent/)
- [ToolbarAnnotationSchemaType](/api/toolbar/type-aliases/toolbarannotationschematype/)
- [ToolbarBlockObjectSchemaType](/api/toolbar/type-aliases/toolbarblockobjectschematype/)
- [ToolbarDecoratorSchemaType](/api/toolbar/type-aliases/toolbardecoratorschematype/)
- [ToolbarInlineObjectSchemaType](/api/toolbar/type-aliases/toolbarinlineobjectschematype/)
- [ToolbarListSchemaType](/api/toolbar/type-aliases/toolbarlistschematype/)
- [ToolbarSchema](/api/toolbar/type-aliases/toolbarschema/)
- [ToolbarStyleSchemaType](/api/toolbar/type-aliases/toolbarstyleschematype/)
## Functions
- [useAnnotationButton](/api/toolbar/functions/useannotationbutton/)
- [useAnnotationPopover](/api/toolbar/functions/useannotationpopover/)
- [useApplicableSchema](/api/toolbar/functions/useapplicableschema/)
- [useBlockObjectButton](/api/toolbar/functions/useblockobjectbutton/)
- [useBlockObjectPopover](/api/toolbar/functions/useblockobjectpopover/)
- [useDecoratorButton](/api/toolbar/functions/usedecoratorbutton/)
- [useHistoryButtons](/api/toolbar/functions/usehistorybuttons/)
- [useInlineObjectButton](/api/toolbar/functions/useinlineobjectbutton/)
- [useInlineObjectPopover](/api/toolbar/functions/useinlineobjectpopover/)
- [useListButton](/api/toolbar/functions/uselistbutton/)
- [useStyleSelector](/api/toolbar/functions/usestyleselector/)
- [useToolbarSchema](/api/toolbar/functions/usetoolbarschema/)
# AnnotationButton
> **AnnotationButton** = `object`
Defined in: toolbar/src/use-annotation-button.ts:276
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### send()
> **send**: (`event`) => `void`
Defined in: toolbar/src/use-annotation-button.ts:290
#### Parameters
##### event
[`AnnotationButtonEvent`](/api/toolbar/type-aliases/annotationbuttonevent/)
#### Returns
`void`
***
### snapshot
> **snapshot**: `object`
Defined in: toolbar/src/use-annotation-button.ts:277
#### matches()
> **matches**: (`state`) => `boolean`
##### Parameters
###### state
`"disabled"` | `"enabled"` | \{ `disabled`: `"inactive"`; \} | \{ `disabled`: `"active"`; \} | \{ `enabled`: `"inactive"`; \} | \{ `enabled`: \{ `inactive`: `"idle"`; \}; \} | \{ `enabled`: \{ `inactive`: `"showing dialog"`; \}; \} | \{ `enabled`: `"active"`; \}
##### Returns
`boolean`
# AnnotationButtonEvent
> **AnnotationButtonEvent** = \{ `type`: `"close dialog"`; \} \| \{ `type`: `"open dialog"`; \} \| \{ `annotation`: \{ `value`: `Record`\<`string`, `unknown`\>; \}; `type`: `"add"`; \} \| \{ `type`: `"remove"`; \}
Defined in: toolbar/src/use-annotation-button.ts:262
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# AnnotationPopover
> **AnnotationPopover** = `object`
Defined in: toolbar/src/use-annotation-popover.ts:261
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### send()
> **send**: (`event`) => `void`
Defined in: toolbar/src/use-annotation-popover.ts:273
#### Parameters
##### event
[`AnnotationPopoverEvent`](/api/toolbar/type-aliases/annotationpopoverevent/)
#### Returns
`void`
***
### snapshot
> **snapshot**: `object`
Defined in: toolbar/src/use-annotation-popover.ts:262
#### context
> **context**: `ActiveContext`
#### matches()
> **matches**: (`state`) => `boolean`
##### Parameters
###### state
`"disabled"` | `"enabled"` | \{ `enabled`: `"inactive"` \| `"active"`; \}
##### Returns
`boolean`
# AnnotationPopoverEvent
> **AnnotationPopoverEvent** = \{ `schemaType`: `AnnotationSchemaType`; `type`: `"remove"`; \} \| \{ `at`: `AnnotationPath`; `props`: \{\[`key`: `string`\]: `unknown`; \}; `type`: `"edit"`; \} \| \{ `type`: `"close"`; \}
Defined in: toolbar/src/use-annotation-popover.ts:244
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# ApplicableSchema
> **ApplicableSchema** = `object`
Defined in: editor/lib/selectors/index.d.ts:9
The set of schema member names applicable at the current selection,
grouped by category.
## Properties
### annotations
> **annotations**: `ReadonlySet`\<`string`\>
Defined in: editor/lib/selectors/index.d.ts:11
***
### blockObjects
> **blockObjects**: `ReadonlySet`\<`string`\>
Defined in: editor/lib/selectors/index.d.ts:14
***
### decorators
> **decorators**: `ReadonlySet`\<`string`\>
Defined in: editor/lib/selectors/index.d.ts:10
***
### inlineObjects
> **inlineObjects**: `ReadonlySet`\<`string`\>
Defined in: editor/lib/selectors/index.d.ts:15
***
### lists
> **lists**: `ReadonlySet`\<`string`\>
Defined in: editor/lib/selectors/index.d.ts:12
***
### styles
> **styles**: `ReadonlySet`\<`string`\>
Defined in: editor/lib/selectors/index.d.ts:13
# BlockObjectButton
> **BlockObjectButton** = `object`
Defined in: toolbar/src/use-block-object-button.ts:151
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### send()
> **send**: (`event`) => `void`
Defined in: toolbar/src/use-block-object-button.ts:161
#### Parameters
##### event
[`BlockObjectButtonEvent`](/api/toolbar/type-aliases/blockobjectbuttonevent/)
#### Returns
`void`
***
### snapshot
> **snapshot**: `object`
Defined in: toolbar/src/use-block-object-button.ts:152
#### matches()
> **matches**: (`state`) => `boolean`
##### Parameters
###### state
`"disabled"` | `"enabled"` | \{ `enabled`: `"idle"`; \} | \{ `enabled`: `"showing dialog"`; \}
##### Returns
`boolean`
# BlockObjectButtonEvent
> **BlockObjectButtonEvent** = \{ `type`: `"close dialog"`; \} \| \{ `type`: `"open dialog"`; \} \| \{ `placement`: `InsertPlacement` \| `undefined`; `type`: `"insert"`; `value`: \{\[`key`: `string`\]: `unknown`; \}; \}
Defined in: toolbar/src/use-block-object-button.ts:135
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# BlockObjectPopover
> **BlockObjectPopover** = `object`
Defined in: toolbar/src/use-block-object-popover.ts:249
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### send()
> **send**: (`event`) => `void`
Defined in: toolbar/src/use-block-object-popover.ts:261
#### Parameters
##### event
[`BlockObjectPopoverEvent`](/api/toolbar/type-aliases/blockobjectpopoverevent/)
#### Returns
`void`
***
### snapshot
> **snapshot**: `object`
Defined in: toolbar/src/use-block-object-popover.ts:250
#### context
> **context**: `ActiveContext`
#### matches()
> **matches**: (`state`) => `boolean`
##### Parameters
###### state
`"disabled"` | `"enabled"` | \{ `enabled`: `"inactive"` \| `"active"`; \}
##### Returns
`boolean`
# BlockObjectPopoverEvent
> **BlockObjectPopoverEvent** = \{ `at`: `BlockPath`; `type`: `"remove"`; \} \| \{ `at`: `BlockPath`; `props`: \{\[`key`: `string`\]: `unknown`; \}; `type`: `"edit"`; \} \| \{ `type`: `"close"`; \}
Defined in: toolbar/src/use-block-object-popover.ts:232
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# DecoratorButton
> **DecoratorButton** = `object`
Defined in: toolbar/src/use-decorator-button.ts:160
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### send()
> **send**: (`event`) => `void`
Defined in: toolbar/src/use-decorator-button.ts:172
#### Parameters
##### event
[`DecoratorButtonEvent`](/api/toolbar/type-aliases/decoratorbuttonevent/)
#### Returns
`void`
***
### snapshot
> **snapshot**: `object`
Defined in: toolbar/src/use-decorator-button.ts:161
#### matches()
> **matches**: (`state`) => `boolean`
##### Parameters
###### state
`"disabled"` | `"enabled"` | \{ `disabled`: `"inactive"`; \} | \{ `disabled`: `"active"`; \} | \{ `enabled`: `"inactive"`; \} | \{ `enabled`: `"active"`; \}
##### Returns
`boolean`
# DecoratorButtonEvent
> **DecoratorButtonEvent** = `object`
Defined in: toolbar/src/use-decorator-button.ts:153
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### type
> **type**: `"toggle"`
Defined in: toolbar/src/use-decorator-button.ts:154
# ExtendAnnotationSchemaType
> **ExtendAnnotationSchemaType** = (`annotation`) => [`ToolbarAnnotationSchemaType`](/api/toolbar/type-aliases/toolbarannotationschematype/)
Defined in: toolbar/src/use-toolbar-schema.ts:27
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### annotation
`AnnotationSchemaType`
## Returns
[`ToolbarAnnotationSchemaType`](/api/toolbar/type-aliases/toolbarannotationschematype/)
# ExtendBlockObjectSchemaType
> **ExtendBlockObjectSchemaType** = (`blockObject`) => [`ToolbarBlockObjectSchemaType`](/api/toolbar/type-aliases/toolbarblockobjectschematype/)
Defined in: toolbar/src/use-toolbar-schema.ts:41
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### blockObject
`BlockObjectSchemaType`
## Returns
[`ToolbarBlockObjectSchemaType`](/api/toolbar/type-aliases/toolbarblockobjectschematype/)
# ExtendDecoratorSchemaType
> **ExtendDecoratorSchemaType** = (`decorator`) => [`ToolbarDecoratorSchemaType`](/api/toolbar/type-aliases/toolbardecoratorschematype/)
Defined in: toolbar/src/use-toolbar-schema.ts:20
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### decorator
`DecoratorSchemaType`
## Returns
[`ToolbarDecoratorSchemaType`](/api/toolbar/type-aliases/toolbardecoratorschematype/)
# ExtendInlineObjectSchemaType
> **ExtendInlineObjectSchemaType** = (`inlineObject`) => [`ToolbarInlineObjectSchemaType`](/api/toolbar/type-aliases/toolbarinlineobjectschematype/)
Defined in: toolbar/src/use-toolbar-schema.ts:48
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### inlineObject
`InlineObjectSchemaType`
## Returns
[`ToolbarInlineObjectSchemaType`](/api/toolbar/type-aliases/toolbarinlineobjectschematype/)
# ExtendListSchemaType
> **ExtendListSchemaType** = (`list`) => [`ToolbarListSchemaType`](/api/toolbar/type-aliases/toolbarlistschematype/)
Defined in: toolbar/src/use-toolbar-schema.ts:34
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### list
`ListSchemaType`
## Returns
[`ToolbarListSchemaType`](/api/toolbar/type-aliases/toolbarlistschematype/)
# ExtendStyleSchemaType
> **ExtendStyleSchemaType** = (`style`) => [`ToolbarStyleSchemaType`](/api/toolbar/type-aliases/toolbarstyleschematype/)
Defined in: toolbar/src/use-toolbar-schema.ts:55
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### style
`StyleSchemaType`
## Returns
[`ToolbarStyleSchemaType`](/api/toolbar/type-aliases/toolbarstyleschematype/)
# HistoryButtons
> **HistoryButtons** = `object`
Defined in: toolbar/src/use-history-buttons.ts:73
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### send()
> **send**: (`event`) => `void`
Defined in: toolbar/src/use-history-buttons.ts:77
#### Parameters
##### event
[`HistoryButtonsEvent`](/api/toolbar/type-aliases/historybuttonsevent/)
#### Returns
`void`
***
### snapshot
> **snapshot**: `object`
Defined in: toolbar/src/use-history-buttons.ts:74
#### matches()
> **matches**: (`state`) => `boolean`
##### Parameters
###### state
`"disabled"` | `"enabled"`
##### Returns
`boolean`
# HistoryButtonsEvent
> **HistoryButtonsEvent** = \{ `type`: `"history.undo"`; \} \| \{ `type`: `"history.redo"`; \}
Defined in: toolbar/src/use-history-buttons.ts:62
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# InlineObjectButton
> **InlineObjectButton** = `object`
Defined in: toolbar/src/use-inline-object-button.ts:145
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### send()
> **send**: (`event`) => `void`
Defined in: toolbar/src/use-inline-object-button.ts:155
#### Parameters
##### event
[`InlineObjectButtonEvent`](/api/toolbar/type-aliases/inlineobjectbuttonevent/)
#### Returns
`void`
***
### snapshot
> **snapshot**: `object`
Defined in: toolbar/src/use-inline-object-button.ts:146
#### matches()
> **matches**: (`state`) => `boolean`
##### Parameters
###### state
`"disabled"` | `"enabled"` | \{ `enabled`: `"idle"`; \} | \{ `enabled`: `"showing dialog"`; \}
##### Returns
`boolean`
# InlineObjectButtonEvent
> **InlineObjectButtonEvent** = \{ `type`: `"close dialog"`; \} \| \{ `type`: `"open dialog"`; \} \| \{ `type`: `"insert"`; `value`: \{\[`key`: `string`\]: `unknown`; \}; \}
Defined in: toolbar/src/use-inline-object-button.ts:130
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# InlineObjectPopover
> **InlineObjectPopover** = `object`
Defined in: toolbar/src/use-inline-object-popover.ts:249
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### send()
> **send**: (`event`) => `void`
Defined in: toolbar/src/use-inline-object-popover.ts:261
#### Parameters
##### event
[`InlineObjectPopoverEvent`](/api/toolbar/type-aliases/inlineobjectpopoverevent/)
#### Returns
`void`
***
### snapshot
> **snapshot**: `object`
Defined in: toolbar/src/use-inline-object-popover.ts:250
#### context
> **context**: `ActiveContext`
#### matches()
> **matches**: (`state`) => `boolean`
##### Parameters
###### state
`"disabled"` | `"enabled"` | \{ `enabled`: `"inactive"` \| `"active"`; \}
##### Returns
`boolean`
# InlineObjectPopoverEvent
> **InlineObjectPopoverEvent** = \{ `at`: `ChildPath`; `type`: `"remove"`; \} \| \{ `at`: `ChildPath`; `props`: \{\[`key`: `string`\]: `unknown`; \}; `type`: `"edit"`; \} \| \{ `type`: `"close"`; \}
Defined in: toolbar/src/use-inline-object-popover.ts:232
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
# ListButton
> **ListButton** = `object`
Defined in: toolbar/src/use-list-button.ts:154
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### send()
> **send**: (`event`) => `void`
Defined in: toolbar/src/use-list-button.ts:166
#### Parameters
##### event
[`ListButtonEvent`](/api/toolbar/type-aliases/listbuttonevent/)
#### Returns
`void`
***
### snapshot
> **snapshot**: `object`
Defined in: toolbar/src/use-list-button.ts:155
#### matches()
> **matches**: (`state`) => `boolean`
##### Parameters
###### state
`"disabled"` | `"enabled"` | \{ `disabled`: `"inactive"`; \} | \{ `disabled`: `"active"`; \} | \{ `enabled`: `"inactive"`; \} | \{ `enabled`: `"active"`; \}
##### Returns
`boolean`
# ListButtonEvent
> **ListButtonEvent** = `object`
Defined in: toolbar/src/use-list-button.ts:147
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### type
> **type**: `"toggle"`
Defined in: toolbar/src/use-list-button.ts:148
# StyleSelector
> **StyleSelector** = `object`
Defined in: toolbar/src/use-style-selector.ts:123
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### send()
> **send**: (`event`) => `void`
Defined in: toolbar/src/use-style-selector.ts:130
#### Parameters
##### event
[`StyleSelectorEvent`](/api/toolbar/type-aliases/styleselectorevent/)
#### Returns
`void`
***
### snapshot
> **snapshot**: `object`
Defined in: toolbar/src/use-style-selector.ts:124
#### context
> **context**: `object`
##### context.activeStyle
> **activeStyle**: `StyleSchemaType`\[`"name"`\] \| `undefined`
#### matches()
> **matches**: (`state`) => `boolean`
##### Parameters
###### state
`"disabled"` | `"enabled"`
##### Returns
`boolean`
# StyleSelectorEvent
> **StyleSelectorEvent** = `object`
Defined in: toolbar/src/use-style-selector.ts:115
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### style
> **style**: `StyleSchemaType`\[`"name"`\]
Defined in: toolbar/src/use-style-selector.ts:117
***
### type
> **type**: `"toggle"`
Defined in: toolbar/src/use-style-selector.ts:116
# ToolbarAnnotationSchemaType
> **ToolbarAnnotationSchemaType** = `AnnotationSchemaType` & `object`
Defined in: toolbar/src/use-toolbar-schema.ts:133
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Type Declaration
### defaultValues?
> `optional` **defaultValues**: `Record`\<`string`, `unknown`\>
### icon?
> `optional` **icon**: `React.ComponentType`\<\{ `className?`: `string`; \}\>
### mutuallyExclusive?
> `optional` **mutuallyExclusive**: `ReadonlyArray`\<`AnnotationDefinition`\[`"name"`\]\>
The annotations this annotation cannot coexist with. The list
replaces the default rule that an annotation is mutually exclusive
with itself:
- Absent: the default applies (adding the annotation removes
existing annotations of the same type in the selection).
- `[]`: exclusive with nothing, not even itself, so same-type
annotations may overlap.
- `['other']`: exclusive with exactly the listed annotations.
Include the annotation's own name to keep self-exclusivity.
### shortcut?
> `optional` **shortcut**: `KeyboardShortcut`
# ToolbarBlockObjectSchemaType
> **ToolbarBlockObjectSchemaType** = `BlockObjectSchemaType` & `object`
Defined in: toolbar/src/use-toolbar-schema.ts:162
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Type Declaration
### defaultValues?
> `optional` **defaultValues**: `Record`\<`string`, `unknown`\>
### icon?
> `optional` **icon**: `React.ComponentType`\<\{ `className?`: `string`; \}\>
### shortcut?
> `optional` **shortcut**: `KeyboardShortcut`
# ToolbarDecoratorSchemaType
> **ToolbarDecoratorSchemaType** = `DecoratorSchemaType` & `object`
Defined in: toolbar/src/use-toolbar-schema.ts:124
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Type Declaration
### icon?
> `optional` **icon**: `React.ComponentType`\<\{ `className?`: `string`; \}\>
### mutuallyExclusive?
> `optional` **mutuallyExclusive**: `ReadonlyArray`\<`DecoratorDefinition`\[`"name"`\]\>
### shortcut?
> `optional` **shortcut**: `KeyboardShortcut`
# ToolbarInlineObjectSchemaType
> **ToolbarInlineObjectSchemaType** = `InlineObjectSchemaType` & `object`
Defined in: toolbar/src/use-toolbar-schema.ts:171
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Type Declaration
### defaultValues?
> `optional` **defaultValues**: `Record`\<`string`, `unknown`\>
### icon?
> `optional` **icon**: `React.ComponentType`\<\{ `className?`: `string`; \}\>
### shortcut?
> `optional` **shortcut**: `KeyboardShortcut`
# ToolbarListSchemaType
> **ToolbarListSchemaType** = `ListSchemaType` & `object`
Defined in: toolbar/src/use-toolbar-schema.ts:155
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Type Declaration
### icon?
> `optional` **icon**: `React.ComponentType`\<\{ `className?`: `string`; \}\>
# ToolbarSchema
> **ToolbarSchema** = `object`
Defined in: toolbar/src/use-toolbar-schema.ts:112
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Properties
### annotations
> **annotations**: `ReadonlyArray`\<[`ToolbarAnnotationSchemaType`](/api/toolbar/type-aliases/toolbarannotationschematype/)\>
Defined in: toolbar/src/use-toolbar-schema.ts:114
***
### blockObjects
> **blockObjects**: `ReadonlyArray`\<[`ToolbarBlockObjectSchemaType`](/api/toolbar/type-aliases/toolbarblockobjectschematype/)\>
Defined in: toolbar/src/use-toolbar-schema.ts:116
***
### decorators
> **decorators**: `ReadonlyArray`\<[`ToolbarDecoratorSchemaType`](/api/toolbar/type-aliases/toolbardecoratorschematype/)\>
Defined in: toolbar/src/use-toolbar-schema.ts:113
***
### inlineObjects
> **inlineObjects**: `ReadonlyArray`\<[`ToolbarInlineObjectSchemaType`](/api/toolbar/type-aliases/toolbarinlineobjectschematype/)\>
Defined in: toolbar/src/use-toolbar-schema.ts:117
***
### lists
> **lists**: `ReadonlyArray`\<[`ToolbarListSchemaType`](/api/toolbar/type-aliases/toolbarlistschematype/)\>
Defined in: toolbar/src/use-toolbar-schema.ts:115
***
### styles
> **styles**: `ReadonlyArray`\<[`ToolbarStyleSchemaType`](/api/toolbar/type-aliases/toolbarstyleschematype/)\>
Defined in: toolbar/src/use-toolbar-schema.ts:118
# ToolbarStyleSchemaType
> **ToolbarStyleSchemaType** = `StyleSchemaType` & `object`
Defined in: toolbar/src/use-toolbar-schema.ts:180
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Type Declaration
### icon?
> `optional` **icon**: `React.ComponentType`\<\{ `className?`: `string`; \}\>
### shortcut?
> `optional` **shortcut**: `KeyboardShortcut`
# comparePoints
> **comparePoints**(`snapshot`, `pointA`, `pointB`): `-1` \| `0` \| `1`
Defined in: compare-points.ts:17
Returns:
- `-1` if `pointA` is before `pointB`
- `0` if `pointA` and `pointB` are equal
- `1` if `pointA` is after `pointB`.
Compares the two points by document order, resolved at any depth. When
the paths are equal, compares offsets.
## Parameters
### snapshot
`TraversalSnapshot`
### pointA
`EditorSelectionPoint`
### pointB
`EditorSelectionPoint`
## Returns
`-1` \| `0` \| `1`
# getAncestor
## Call Signature
> **getAncestor**\<`TMatch`\>(`snapshot`, `path`, `options`): \{ `node`: `TMatch`; `path`: `Path`; \} \| `undefined`
Defined in: get-ancestor.ts:17
Find an ancestor of the node at a given path that matches a predicate.
Does not check the node at the path itself, only its ancestors.
`mode: 'lowest'` (default) returns the nearest matching ancestor.
`mode: 'highest'` returns the outermost matching ancestor.
When `match` is a type predicate, the returned `node` narrows to that type.
### Type Parameters
#### TMatch
`TMatch` *extends* `PortableTextBlock`
### Parameters
#### snapshot
`TraversalSnapshot`
#### path
`Path`
#### options
##### match
(`node`, `path`) => `node is TMatch`
##### mode?
`"lowest"` \| `"highest"`
### Returns
\{ `node`: `TMatch`; `path`: `Path`; \} \| `undefined`
## Call Signature
> **getAncestor**(`snapshot`, `path`, `options`): \{ `node`: `PortableTextBlock`; `path`: `Path`; \} \| `undefined`
Defined in: get-ancestor.ts:28
### Parameters
#### snapshot
`TraversalSnapshot`
#### path
`Path`
#### options
##### match
(`node`, `path`) => `boolean`
##### mode?
`"lowest"` \| `"highest"`
### Returns
\{ `node`: `PortableTextBlock`; `path`: `Path`; \} \| `undefined`
# getAncestors
> **getAncestors**(`snapshot`, `path`): `object`[]
Defined in: get-ancestors.ts:27
Get all ancestors of the node at a given path, from nearest to furthest.
For a path like [{_key:'t1'}, 'rows', {_key:'r1'}, 'cells', {_key:'c1'}],
the ancestors are (nearest first):
[{_key:'t1'}, 'rows', {_key:'r1'}]
[{_key:'t1'}]
Walks from root to the target in a single pass collecting each ancestor
as it goes.
Every ancestor is a `PortableTextBlock`: only text blocks and object
nodes can contain children.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
`object`[]
# getAnnotation
> **getAnnotation**(`snapshot`, `path`): \{ `node`: `PortableTextObject`; `path`: `Path`; \} \| `undefined`
Defined in: get-annotation.ts:18
Get the annotation at a given path.
Annotations live in `markDefs` on a text block, alongside `children`
rather than inside it, so they aren't reachable through `getNode`.
`getAnnotation` resolves a path of the shape
`[..., {_key: block}, 'markDefs', {_key: annotation}, ...]` to the
annotation node on the enclosing text block.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
\{ `node`: `PortableTextObject`; `path`: `Path`; \} \| `undefined`
# getBlock
> **getBlock**(`snapshot`, `path`): \{ `node`: `PortableTextBlock`; `path`: `Path`; \} \| `undefined`
Defined in: is-block.ts:37
Get the node at the given path if it is a block.
Returns the node narrowed to PortableTextBlock, or undefined if the node
doesn't exist or is not a block.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
\{ `node`: `PortableTextBlock`; `path`: `Path`; \} \| `undefined`
# getChildren
> **getChildren**(`snapshot`, `path`): `object`[]
Defined in: get-children.ts:21
Get the children of a node at a given path.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
`object`[]
# getContainer
> **getContainer**(`snapshot`, `path`): \{ `node`: `Node`; `path`: `Path`; \} \| `undefined`
Defined in: get-container.ts:12
Get the registered editable container at a given path.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
\{ `node`: `Node`; `path`: `Path`; \} \| `undefined`
# getContainerChildren
> **getContainerChildren**(`containers`, `node`, `parent?`): \{ `children`: `Node`[]; `container`: `RegisteredContainer`; \} \| `undefined`
Defined in: get-container-children.ts:24
Resolve a container node's editable child array.
Returns `{children, container}` for a node registered as a container:
`children` is the node's editable child array, and `container` is the
node's own container registration. Read `container.field.name` for the
path segment that reaches `children`, and thread `container` back in as
`parent` when descending into them.
Returns `undefined` for anything that is not a container: text blocks,
spans, leaves, and unregistered objects. It is node-based and resolves
in one step with no path re-walk, so recursive descent over containers
is linear in nesting depth. The caller seeds the document root from
`context.value` itself.
:::caution[Beta]
This API should not be used in production and may be trimmed from a public release.
:::
## Parameters
### containers
`Containers`
### node
`Node`
### parent?
`RegisteredContainer`
## Returns
\{ `children`: `Node`[]; `container`: `RegisteredContainer`; \} \| `undefined`
# getEnclosingBlock
## Call Signature
> **getEnclosingBlock**\<`TMatch`\>(`snapshot`, `path`, `options`): \{ `node`: `TMatch`; `path`: `Path`; \} \| `undefined`
Defined in: get-enclosing-block.ts:25
Walk up from a path to find the nearest enclosing block.
Returns the node at the path if it is a block, otherwise the first ancestor
that is a block. Works at any depth — inside a container this returns the
container-internal block, not the outer container.
With `match`, returns the first enclosing block that also satisfies the
predicate. When `match` is a type predicate, the returned `node` narrows
to that type.
`mode: 'lowest'` (default) returns the innermost enclosing block; the node
at the path itself counts. `mode: 'highest'` returns the outermost
ancestor that matches, falling back to the node at the path only if no
ancestor does.
### Type Parameters
#### TMatch
`TMatch` *extends* `PortableTextBlock`
### Parameters
#### snapshot
`TraversalSnapshot`
#### path
`Path`
#### options
##### match
(`node`, `path`) => `node is TMatch`
##### mode?
`"lowest"` \| `"highest"`
### Returns
\{ `node`: `TMatch`; `path`: `Path`; \} \| `undefined`
## Call Signature
> **getEnclosingBlock**(`snapshot`, `path`, `options?`): \{ `node`: `PortableTextBlock`; `path`: `Path`; \} \| `undefined`
Defined in: get-enclosing-block.ts:36
### Parameters
#### snapshot
`TraversalSnapshot`
#### path
`Path`
#### options?
##### match?
(`node`, `path`) => `boolean`
##### mode?
`"lowest"` \| `"highest"`
### Returns
\{ `node`: `PortableTextBlock`; `path`: `Path`; \} \| `undefined`
# getFirstChild
> **getFirstChild**(`snapshot`, `path`): \{ `node`: `Node`; `path`: `Path`; \} \| `undefined`
Defined in: get-first-child.ts:11
Get the first child of a node at a given path.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
\{ `node`: `Node`; `path`: `Path`; \} \| `undefined`
# getLastChild
> **getLastChild**(`snapshot`, `path`): \{ `node`: `Node`; `path`: `Path`; \} \| `undefined`
Defined in: get-last-child.ts:11
Get the last child of a node at a given path.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
\{ `node`: `Node`; `path`: `Path`; \} \| `undefined`
# getLeaf
> **getLeaf**(`snapshot`, `path`, `options`): \{ `node`: `Node`; `path`: `Path`; \} \| `undefined`
Defined in: get-leaf.ts:14
Get the deepest leaf node starting from a path, walking toward either the
start or end edge. A leaf is any node that has no children according to the
traversal context.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
### options
#### edge
`"start"` \| `"end"`
## Returns
\{ `node`: `Node`; `path`: `Path`; \} \| `undefined`
# getNode
> **getNode**(`snapshot`, `path`): \{ `node`: `Node`; `path`: `Path`; \} \| `undefined`
Defined in: get-node.ts:36
Get the node at a given path.
The path can be either keyed (KeyedSegment + field name strings) or
indexed (numbers). Keyed segments are resolved by matching `_key`,
field name strings name a structural descent into the previous
node's children, and numbers are resolved by index.
The returned `path` always identifies the returned node: segments
are keyed wherever the node has a usable `_key` (numeric indices are
converted to `KeyedSegment`s), and stay numeric for nodes
normalization has not keyed yet (a `{_key: undefined}` segment would
not distinguish keyless siblings). Any trailing segments in the
input that point outside the value tree — e.g. an object node's
primitive field, or an annotation reached via `'markDefs'` on a text
block — are stripped so that
`getNode(snapshot, entry.path).node === entry.node`.
The walk stops when a string segment names a field that isn't the
current node's structural child array. Annotations live in
`markDefs` on a text block, alongside `children` rather than inside
it, so `getNode` resolves an annotation path to the enclosing text
block. Use `getAnnotation` to resolve the annotation itself.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
\{ `node`: `Node`; `path`: `Path`; \} \| `undefined`
# getParent
## Call Signature
> **getParent**\<`TMatch`\>(`snapshot`, `path`, `options`): \{ `node`: `TMatch`; `path`: `Path`; \} \| `undefined`
Defined in: get-parent.ts:18
Get the parent of a node at a given path.
A parent has children, so it is always a `PortableTextBlock` (text block
or object node).
When `match` is provided and the parent does not satisfy it, returns
`undefined`.
### Type Parameters
#### TMatch
`TMatch` *extends* `PortableTextBlock`
### Parameters
#### snapshot
`TraversalSnapshot`
#### path
`Path`
#### options
##### match
(`node`, `path`) => `node is TMatch`
### Returns
\{ `node`: `TMatch`; `path`: `Path`; \} \| `undefined`
## Call Signature
> **getParent**(`snapshot`, `path`, `options?`): \{ `node`: `PortableTextBlock`; `path`: `Path`; \} \| `undefined`
Defined in: get-parent.ts:28
### Parameters
#### snapshot
`TraversalSnapshot`
#### path
`Path`
#### options?
##### match?
(`node`, `path`) => `boolean`
### Returns
\{ `node`: `PortableTextBlock`; `path`: `Path`; \} \| `undefined`
# getPathSubSchema
> **getPathSubSchema**(`snapshot`, `path`): `Schema`
Defined in: get-path-sub-schema.ts:16
Return the `Schema` view that applies at a given path.
For paths at the root of the document, or for paths where no ancestor is
a registered container, returns the top-level schema. For paths inside a
container, walks ancestors to find the nearest container and returns the
sub-schema derived from its `of` declaration.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
`Schema`
# getSibling
## Call Signature
> **getSibling**\<`TMatch`\>(`snapshot`, `path`, `options`): \{ `node`: `TMatch`; `path`: `Path`; \} \| `undefined`
Defined in: get-sibling.ts:19
Get a sibling of the node at a given path.
Without `match`, returns the immediate next or previous sibling.
With `match`, returns the first sibling in `direction` that satisfies
the predicate.
When `match` is a type predicate, the returned `node` narrows to that type.
### Type Parameters
#### TMatch
`TMatch` *extends* `Node`
### Parameters
#### snapshot
`TraversalSnapshot`
#### path
`Path`
#### options
##### direction
`"next"` \| `"previous"`
##### match
(`node`, `path`) => `node is TMatch`
### Returns
\{ `node`: `TMatch`; `path`: `Path`; \} \| `undefined`
## Call Signature
> **getSibling**(`snapshot`, `path`, `options`): \{ `node`: `Node`; `path`: `Path`; \} \| `undefined`
Defined in: get-sibling.ts:30
### Parameters
#### snapshot
`TraversalSnapshot`
#### path
`Path`
#### options
##### direction
`"next"` \| `"previous"`
##### match?
(`node`, `path`) => `boolean`
### Returns
\{ `node`: `Node`; `path`: `Path`; \} \| `undefined`
# getSpan
> **getSpan**(`snapshot`, `path`): \{ `node`: `PortableTextSpan`; `path`: `Path`; \} \| `undefined`
Defined in: get-span.ts:11
Get the span node at a given path.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
\{ `node`: `PortableTextSpan`; `path`: `Path`; \} \| `undefined`
# getText
> **getText**(`snapshot`, `path`): `string` \| `undefined`
Defined in: get-text.ts:12
Get the concatenated text content of the node at a given path.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
`string` \| `undefined`
# getTextBlock
> **getTextBlock**(`snapshot`, `path`): \{ `node`: `PortableTextTextBlock`; `path`: `Path`; \} \| `undefined`
Defined in: get-text-block.ts:11
Get the text block node at a given path.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
\{ `node`: `PortableTextTextBlock`; `path`: `Path`; \} \| `undefined`
# getUnionSchema
> **getUnionSchema**(`schema`, `containers`): `Schema`
Defined in: get-union-schema.ts:28
Return a `Schema` that contains every named member declared anywhere
in the editor's schema graph that is reachable from a position where text
is edited - the root schema merged with the sub-schema of every registered
container whose field accepts text blocks, deduped by name. Useful for
rendering a static toolbar whose buttons stay stable across selection
moves while still reflecting everything that could plausibly be edited or
inserted somewhere.
Containers whose field does NOT accept text blocks (e.g. a `table`
container whose `rows` field only accepts `row` objects, or a `row`
container whose `cells` field only accepts `cell` objects) are
**structural**: their immediate `of` types are organizational, not
insertable user content. Those structural types are excluded from the
union. Their nested text-block-accepting descendants (e.g. a `cell`
that contains a `content` field of `{type: 'block'}`) are reached via
those descendants' own container registration.
Pair with `getPathSubSchema` (or a path-based intersection across a
range) to determine which of the union's members are applicable at the
current selection.
## Parameters
### schema
`Schema`
### containers
`Containers`
## Returns
`Schema`
# hasNode
> **hasNode**(`snapshot`, `path`): `boolean`
Defined in: has-node.ts:10
Check if a node exists at a given path.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
`boolean`
# isBlock
> **isBlock**(`snapshot`, `path`): `boolean`
Defined in: is-block.ts:19
Determine if a node at the given path is a block.
A node is a block if its parent is not a text block. Top-level nodes
(direct children of the editor) are always blocks. Children of text blocks
(spans and inline objects) are not blocks. Children of containers are
blocks within that container.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
`boolean`
# isInline
> **isInline**(`snapshot`, `path`): `boolean`
Defined in: is-inline.ts:13
Determine if a node at the given path is inline.
A node is inline if its parent is a text block. This is the inverse of
`isBlock`. Top-level nodes are never inline.
## Parameters
### snapshot
`TraversalSnapshot`
### path
`Path`
## Returns
`boolean`
# isLeafObject
> **isLeafObject**(`snapshot`, `node`, `path`): `node is PortableTextObject`
Defined in: is-leaf-object.ts:15
Check if a node is a leaf object: an object node that has no editable
children (not a container).
Returns true for block objects and inline objects that don't have
registered editable content (containers).
## Parameters
### snapshot
`TraversalSnapshot`
### node
`unknown`
### path
`Path`
## Returns
`node is PortableTextObject`
# isObject
> **isObject**(`snapshot`, `node`): `node is PortableTextObject`
Defined in: is-object.ts:10
Check if a node is an object node (not a text block or span).
## Parameters
### snapshot
`TraversalSnapshot`
### node
`unknown`
## Returns
`node is PortableTextObject`
# pathContains
> **pathContains**(`ancestor`, `descendant`): `boolean`
Defined in: path-contains.ts:10
Returns true if `ancestor` is equal to `descendant`, or if `descendant`
lives anywhere inside `ancestor`'s subtree.
## Parameters
### ancestor
`Path`
### descendant
`Path`
## Returns
`boolean`
# rangeIntersects
> **rangeIntersects**(`snapshot`, `range`, `target`): `boolean`
Defined in: range-intersects.ts:30
Returns true if `range` and the supplied `target` intersect. The target
may be a `Path`, an `EditorSelectionPoint`, or another
`EditorSelection`.
For a `Path` or `EditorSelectionPoint` target, "intersect" means the
target lies at or between `range`'s start and end edges (inclusive).
For an `EditorSelection` target, "intersect" means either endpoint of
`target` lies inside `range`, or `range` strictly encloses `target`.
Pass `snapshot.context.selection` as `range` to ask the question against
the editor's current selection.
Returns `false` when either `range` or `target` is `null`.
## Parameters
### snapshot
`TraversalSnapshot`
### range
`EditorSelection`
### target
`Path` | `EditorSelectionPoint` | `EditorSelection`
## Returns
`boolean`
# @portabletext/editor
## Functions
- [comparePoints](/api/traversal/functions/comparepoints/)
- [getAncestor](/api/traversal/functions/getancestor/)
- [getAncestors](/api/traversal/functions/getancestors/)
- [getAnnotation](/api/traversal/functions/getannotation/)
- [getBlock](/api/traversal/functions/getblock/)
- [getChildren](/api/traversal/functions/getchildren/)
- [getContainer](/api/traversal/functions/getcontainer/)
- [getContainerChildren](/api/traversal/functions/getcontainerchildren/)
- [getEnclosingBlock](/api/traversal/functions/getenclosingblock/)
- [getFirstChild](/api/traversal/functions/getfirstchild/)
- [getLastChild](/api/traversal/functions/getlastchild/)
- [getLeaf](/api/traversal/functions/getleaf/)
- [getNode](/api/traversal/functions/getnode/)
- [getParent](/api/traversal/functions/getparent/)
- [getPathSubSchema](/api/traversal/functions/getpathsubschema/)
- [getSibling](/api/traversal/functions/getsibling/)
- [getSpan](/api/traversal/functions/getspan/)
- [getText](/api/traversal/functions/gettext/)
- [getTextBlock](/api/traversal/functions/gettextblock/)
- [getUnionSchema](/api/traversal/functions/getunionschema/)
- [hasNode](/api/traversal/functions/hasnode/)
- [isBlock](/api/traversal/functions/isblock/)
- [isInline](/api/traversal/functions/isinline/)
- [isLeafObject](/api/traversal/functions/isleafobject/)
- [isObject](/api/traversal/functions/isobject/)
- [pathContains](/api/traversal/functions/pathcontains/)
- [rangeIntersects](/api/traversal/functions/rangeintersects/)
# HTML to Portable Text
> Convert HTML content to Portable Text using the official conversion packages.
import {TabItem, Tabs} from '@astrojs/starlight/components'
import {PackageManagers} from 'starlight-package-managers'
Convert HTML strings to Portable Text blocks. This is useful for migrating content from a CMS that stores HTML, processing pasted content from web pages, or importing content from WordPress, Google Docs, or Notion.
:::note[Prerequisites]
This guide covers `@portabletext/html` **v1.x** and `@portabletext/block-tools` **v5.x** ([changelog](https://github.com/portabletext/editor/releases)). Both packages require Node.js 20.19+ or 22.12+.
:::
## Which package?
**Using Sanity?** Use `@portabletext/block-tools`. It accepts your Sanity schema directly.
**Everything else?** Use `@portabletext/html`. It works standalone with no Sanity dependency.
Both packages use the same conversion engine (block-tools delegates to html internally). Custom rules are interchangeable between them, and they produce identical output for identical schemas.
## Install
## Basic usage
```ts
import {htmlToPortableText} from '@portabletext/html'
const blocks = htmlToPortableText('
Hello world
')
```
In the browser, the package uses the built-in `DOMParser`. In Node.js, you need to provide a `parseHtml` function:
```ts
import {htmlToPortableText} from '@portabletext/html'
import {JSDOM} from 'jsdom'
const blocks = htmlToPortableText(html, {
parseHtml: (html) => new JSDOM(html).window.document,
})
```
```ts
import {htmlToBlocks} from '@portabletext/block-tools'
import {Schema} from '@sanity/schema'
import {JSDOM} from 'jsdom'
// Get the block content type from your Sanity schema
const defaultSchema = Schema.compile({
name: 'myBlog',
types: [{
type: 'object',
name: 'blogPost',
fields: [{
name: 'body',
type: 'array',
of: [{type: 'block'}],
}],
}],
})
const blockContentType = defaultSchema
.get('blogPost')
.fields.find((f) => f.name === 'body').type
const blocks = htmlToBlocks(html, blockContentType, {
parseHtml: (html) => new JSDOM(html).window.document,
})
```
## Node.js setup
In the browser, HTML parsing works automatically via `DOMParser`. In Node.js, there is no built-in DOM, so you must provide a `parseHtml` function. The package throws a descriptive error if you forget.
[JSDOM](https://github.com/jsdom/jsdom) is the most common choice:
```ts
import {JSDOM} from 'jsdom'
// Pass to either package
const options = {
parseHtml: (html) => new JSDOM(html).window.document,
}
```
Lighter alternatives like [linkedom](https://github.com/WebReflection/linkedom) and [happy-dom](https://github.com/capricorn86/happy-dom) also work. Any library that returns a standard `Document` object is compatible.
## What converts by default
The converter maps semantic HTML elements to Portable Text:
| HTML | Portable Text |
| --------------------------- | --------------------------------------------- |
| `
,
}),
defineDecorator({
type: 'strong',
render: ({children}) => {children},
}),
defineAnnotation({
type: 'link',
render: ({annotation, children}) =>
typeof annotation.href === 'string' ? (
{children}
) : (
children
),
}),
]
function App() {
return (
)
}
```
`annotation` is the markDef object from the block's `markDefs`: `{_key, _type, ...fields}`. Its fields type as `unknown` because they depend on the schema, so narrow with `typeof` before use; the fallback renders `children` untouched, matching the engine default. Each render callback is a plain function call, not a component: when a render needs hooks, return a component instead, `render: (props) => `.
Keep `nodes` at module scope, as above: a fresh array identity on every render makes `NodePlugin` unregister and re-register every keystroke.
## Subtree ownership
A block-level registration (a text block, block object, or container) owns everything rendered inside it, its rendering subtree. Unregistered node types inside it fall back to the engine defaults: a registered text block holding an unregistered inline object still renders that inline object through the engine's default wrapper, not through markup you control. Register a node type when you need to own its markup, wherever it appears:
```tsx
const nodes = [
defineTextBlock({
type: 'block',
render: ({attributes, children}) =>
{children}
,
}),
defineInlineObject({
type: 'stock-ticker',
render: (props) =>
typeof props.node.symbol === 'string' ? (
{props.children}
{props.node.symbol}
) : (
props.renderDefault(props)
),
}),
]
```
## Dispatch precedence
At a given position, a positional registration (one scoped through a container or text block's own `of`, see [Containers](/editor/concepts/containers/)) beats a global registration, which beats the engine default. Within a level, an exact `type` match beats a `'*'` catch-all:
```tsx
const nodes = [
// `strong` hits the exact match...
defineDecorator({
type: 'strong',
render: ({children}) => {children},
}),
// ...every other decorator hits the catch-all.
defineDecorator({
type: '*',
render: ({decorator, children}) => (
{children}
),
}),
]
```
[Narrow rendering with `of`](/editor/concepts/containers/#narrow-rendering-with-of) covers how far a positional entry's scope reaches and what it falls back to when it omits `render`.
## `renderDefault`
Every render receives `renderDefault`, a function that renders the engine's minimal wrapper for that position. Call it to fall back, or to wrap the default instead of replacing it:
```tsx
render: (props) => props.renderDefault(props)
```
Its most common use is the fallback branch of a field-presence check: a document can carry a partially filled value, and the engine default beats rendering nothing:
```tsx
defineBlockObject({
type: 'image',
render: (props) =>
typeof props.node.src === 'string' ? (
{props.children}
) : (
props.renderDefault(props)
),
})
```
The `contentEditable={false}`/`draggable` wrapper is the block-object render contract; the [custom blocks guide](/editor/guides/custom-blocks/) covers it in full.
`renderDefault` is the engine default at any position: it never chains back to a global registration's render, even from inside a positional one. PTE has one user layer plus positional overrides, and the engine default is the canonical fallback everywhere. For block-level, span, and inline-object registrations the default is a minimal wrapper; for decorators the default is identity, the engine applies no decorator markup of its own. For annotations the default is identity too, but every known annotation renders inside an engine-owned anchor span the engine adds regardless of which render fires.
## Plugins for lists and drag-and-drop
Two rendering concerns ship as plugins instead of registration props:
- List numbering: your text-block render reads `node.listItem` and `node.level` for list markup, and [`@portabletext/plugin-list-index`](https://github.com/portabletext/editor/tree/main/packages/plugin-list-index) computes the 1-based list index at any path, correct across nesting, remote edits, and non-list blocks interrupting a list.
- Drop indicators: pointer-driven UI rendered by you. [`@portabletext/plugin-dnd`](https://github.com/portabletext/editor/tree/main/packages/plugin-dnd) tracks the drop position from the editor's public `drag.*` events.
Both plugins follow the same pattern: a provider inside `EditorProvider`, and a hook read from a component your `render` returns, not inline in the `render` callback, since hooks can't run there:
```tsx
import type {TextBlockRenderProps} from '@portabletext/editor'
import {useListIndex} from '@portabletext/plugin-list-index'
const nodes = [
defineTextBlock({
type: 'block',
render: (props) => ,
}),
]
function TextBlock(props: TextBlockRenderProps) {
const listIndex = useListIndex(props.path)
return (
)
}
```
`useListIndex` reads from `ListIndexProvider`, mounted inside `EditorProvider`. Each plugin's README carries the full recipe, including a reference `DropIndicator` implementation.
:::note[Migrating from the render props?]
If your editor still renders through the render props from the previous major, removed in this one (`renderBlock`, `renderChild`, `renderStyle`, `renderListItem`, `renderDecorator`, `renderAnnotation`), each has a registration equivalent, and the engine dispatches per `_type`, so you can migrate one kind at a time. The [migration guide](/editor/guides/migrate-render-props/) walks through it.
:::
# Traversal
> Pure functions that answer questions about the editor's value tree, given a path and a snapshot.
import {LinkCard} from '@astrojs/starlight/components'
The traversal API is a set of pure functions that answer questions about the editor's value tree: what node lives at this path, what is its parent, does this range intersect that selection. They take a snapshot and a path (or two) and return an answer, with no side effects and no dependency on the current selection.
```ts
import * as traversal from '@portabletext/editor/traversal'
```
## Snapshots
The lookups and family walkers below take an `EditorSnapshot` as their first argument. You already hold one in the places where you'd reach for traversal: a selector receives it as its only argument, a behavior guard or action receives it as `snapshot`, and `editor.getSnapshot()` returns one at event time, for example inside a plugin's `useEffect`. A few functions work from narrower inputs instead: `pathContains` compares two paths with no snapshot at all, and `getUnionSchema` takes a schema and a container map, both readable off `snapshot.context`.
```ts
import type {EditorSelector} from '@portabletext/editor'
import * as traversal from '@portabletext/editor/traversal'
const hasFooBlock: EditorSelector = (snapshot) =>
traversal.hasNode(snapshot, [{_key: 'foo'}])
```
There's no public way to build a snapshot yourself. Take the one your call site already has.
## Paths
A path is a sequence of keyed segments and field names: `{_key: 'foo'}` addresses a node by its key, and a string like `'children'` names the array field to descend into next. Nested containers chain the same shape one level deeper. Reaching a cell in a table looks like:
```ts
const cellPath = [{_key: 't1'}, 'rows', {_key: 'r1'}, 'cells', {_key: 'c1'}]
```
`getNode` and the other lookups also accept numeric indexes in place of a keyed segment, but the path on the returned result is always fully keyed: an index like `0` resolves to whatever node currently sits there, and the answer comes back addressed by that node's `_key`, not by the index you passed in.
## Entries
A lookup like `getNode` or `getParent` doesn't return the node on its own. It returns the node together with its canonical keyed path, fully keyed even when the path you passed in used an index. That path is exactly what you'd pass into the next call, so results chain: get a node, get its parent, get the parent's first child, without re-deriving a path by hand at each step.
## Finding and walking nodes
`getNode` resolves any path to its node and canonical path, or `undefined` if nothing lives there. `hasNode` asks the same question as a boolean.
Typed lookups narrow to a specific shape and return `undefined` if the node at the path isn't that shape:
- `getBlock` - a block: a text block or an object node at block position
- `getTextBlock` - a text block specifically
- `getSpan` - a span
- `getAnnotation` - resolves an annotation reference. Annotations live in `markDefs` on a text block, alongside `children` rather than inside it, so `getNode` can't reach one; use `getAnnotation` for a path like `[..., {_key: block}, 'markDefs', {_key: annotation}]`.
- `getContainer` - the registered editable container at a path, or `undefined` if the node there isn't one
`getText` sits alongside these: it returns the concatenated text content of the node at a path, walking its descendants for a span's text when the node itself isn't a span.
Family walkers move relative to a path:
- `getParent` - the enclosing text block or object node
- `getAncestor` / `getAncestors` - one matching ancestor, or every ancestor from nearest to furthest
- `getChildren` / `getFirstChild` / `getLastChild` - a node's children
- `getSibling` - the next or previous sibling, optionally the first one matching a predicate
- `getEnclosingBlock` - the node at the path if it's already a block, otherwise the nearest block ancestor
- `getLeaf` - walks from a path toward the `start` or `end` edge and returns the deepest leaf it reaches
## Narrowing
`isBlock` and `isInline` classify a path by its parent: a node is a block unless its parent is a text block, and inline is the inverse. Children of a container are blocks within that container, the same way top-level nodes are blocks within the document. `isObject` classifies a node value directly and is true for anything that isn't a text block or span. `isLeafObject` takes the node's path as well as the node, and narrows further to an object with no editable children, an object that isn't a container.
Reach for a typed lookup like `getSpan` or `getTextBlock` when the node also has to exist: it does the existence check and the narrowing in one call. Reach for a predicate like `isBlock` when you already have the node and only need the classification.
## Points and ranges
`comparePoints` orders two `EditorSelectionPoint`s by document position, returning `-1`, `0`, or `1`. `pathContains` asks whether one path's subtree contains another, comparing path shape alone with no snapshot and no notion of selection. `rangeIntersects` asks whether an `EditorSelection` overlaps a path, a point, or another selection.
A behavior guard that only wants to run when the selection sits inside a specific subtree reaches for `rangeIntersects` with the selection on the snapshot:
```ts
defineBehavior({
on: 'delete.backward',
guard: ({snapshot}) => {
const rowPath = [{_key: 't1'}, 'rows', {_key: 'r1'}]
return traversal.rangeIntersects(
snapshot,
snapshot.context.selection,
rowPath,
)
},
actions: [
() => [
/* ... */
],
],
})
```
## Schema at a position
`getPathSubSchema` returns the `Schema` view that applies at a path: the top-level schema outside any container, or the sub-schema derived from the nearest enclosing container's `of` declaration. See [Containers](/editor/concepts/containers/) for how that sub-schema is built.
`getUnionSchema` returns a `Schema` merging every named member reachable from any position where text is edited: the root schema plus the sub-schema of every registered container whose field accepts text blocks, deduped by name. It takes the schema and the container map directly rather than a snapshot, both available as `snapshot.context.schema` and `snapshot.context.containers`. Where `getPathSubSchema` answers "what applies right here," `getUnionSchema` answers "what could ever apply somewhere," useful for a toolbar whose buttons stay stable across selection moves.
## Traversal and selectors
Selectors build on the same snapshot and add current-selection semantics: `getFocusBlock` finds a block by asking where the selection focus is, using traversal underneath. Reach for traversal directly when you already hold a path, and for a selector when the question starts from the selection itself.
# Getting started
> Install the Portable Text Editor and build your first block content editing experience.
import {
CardGrid,
LinkCard,
Steps,
TabItem,
Tabs,
} from '@astrojs/starlight/components'
import {PackageManagers} from 'starlight-package-managers'
This guide walks you through installing and configuring the Portable Text Editor. By the end, you'll have a working block content editor with custom styles, decorators, and a toolbar.
:::tip[Just need to render Portable Text?]
If you already have Portable Text content and want to display it, see [Render Portable Text](/rendering/) instead.
:::
You'll need to:
- Create a schema that defines your content elements.
- Create a toolbar to toggle and insert these elements.
- Set up rendering for your text blocks and inline formatting, like bold and italic.
- Render the editor.
## Parts of the editor
Before starting, it helps to understand the components that make up the editor.
- **Schema:** Describes the type of content the editor accepts. Think of this as the foundation for configuring the editor.
- **`EditorProvider`:** Supplies the schema and initial state to the editor.
- **`EventListenerPlugin`:** Listens to events emitted by the editor. Commonly used to update application state.
- **Node registrations:** Own how each content element renders, mounted through `NodePlugin`. [Rendering](/editor/concepts/rendering/) covers the model.
- **Toolbars:** UI elements that interact with the editor.
- **`PortableTextEditable`:** The core editor component. Hosts the editable surface and manages behavior.
## Add the library to your project
Start by installing the editor (it requires React 19.2.8 or later):
Next, import the components and types you'll need:
```tsx
// App.tsx
import {
defineDecorator,
defineSchema,
defineTextBlock,
EditorProvider,
PortableTextEditable,
} from '@portabletext/editor'
import type {PortableTextBlock} from '@portabletext/editor'
import {EventListenerPlugin, NodePlugin} from '@portabletext/editor/plugins'
```
You won't need all of these right away, but you can add them now.
## Define your schema
Before you can render the editor, you need a schema. The editor schema configures the types of content rendered by the editor.
Start with a schema that includes some common formatting elements.
:::note
This guide includes a limited set of schema types to get you started. See the [rendering guide](/editor/guides/custom-rendering/) for mark examples, and the [custom blocks guide](/editor/guides/custom-blocks/) for block and inline objects.
:::
```tsx
// App.tsx
// ...
const schemaDefinition = defineSchema({
// Decorators are simple marks that don't hold any data
decorators: [{name: 'strong'}, {name: 'em'}, {name: 'underline'}],
// Styles apply to entire text blocks
// There's always a 'normal' style that can be considered the paragraph style
styles: [
{name: 'normal'},
{name: 'h1'},
{name: 'h2'},
{name: 'h3'},
{name: 'blockquote'},
],
// The types below are left empty for this example.
// See the rendering guide to learn more about each type.
// Annotations are more complex marks that can hold data (for example, hyperlinks).
annotations: [],
// Lists apply to entire text blocks as well (for example, bullet, numbered).
// Lists render inside your registered text-block render; ordered-list
// numbering comes from `@portabletext/plugin-list-index`.
lists: [],
// Inline objects hold arbitrary data that can be inserted into the text (for example, custom emoji).
inlineObjects: [],
// Block objects hold arbitrary data that live side-by-side with text blocks (for example, images, code blocks, and tables).
blockObjects: [],
})
```
## Render the editor
With a schema defined, you have enough to render the editor. It won't do much yet, but you can confirm your progress.
Add `react` and `useState`, then scaffold out a basic application component:
```tsx
// app.tsx
import {
defineDecorator,
defineSchema,
defineTextBlock,
EditorProvider,
PortableTextEditable,
} from '@portabletext/editor'
import type {PortableTextBlock} from '@portabletext/editor'
import {EventListenerPlugin, NodePlugin} from '@portabletext/editor/plugins'
import {useState} from 'react'
const schemaDefinition = defineSchema({
/* your schema from the previous step */
})
function App() {
// Set up the initial state getter and setter. Leave the starting value as undefined for now.
const [value, setValue] = useState | undefined>(
undefined,
)
return (
<>
{
if (event.type === 'mutation') {
setValue(event.value)
}
}}
/>
>
)
}
export default App
```
Include the `App` component in your application and run it. You should see an outlined editor that accepts text, but doesn't do much else.
## Set up rendering for schema elements
At this point the editor renders every text block as plain text, whatever its style. Fix that by registering a `defineTextBlock` node for the text blocks and `defineDecorator` nodes for the marks. The [Rendering](/editor/concepts/rendering/) page covers the model these registrations share.
If you're maintaining an editor that rendered through the `renderStyle`, `renderBlock`, `renderListItem`, `renderDecorator`, and `renderAnnotation` props, removed in this major, see the [migration guide](/editor/guides/migrate-render-props/) to move to node registrations instead of following this section from scratch.
Start by registering the text block render with `defineTextBlock`. The editor dispatches every text block to this callback. Your callback owns the block's wrapper element, so spread `props.attributes` on the outermost element you return, and use the block's `style` to pick the element.
```tsx
const textBlock = defineTextBlock({
type: 'block',
render: (props) => {
if (props.node.style === 'h1') {
return
{props.children}
}
if (props.node.style === 'h2') {
return
{props.children}
}
if (props.node.style === 'h3') {
return
{props.children}
}
if (props.node.style === 'blockquote') {
return
{props.children}
}
return
{props.children}
},
})
```
Marks (decorators and annotations) join the same `nodes` array. Registrations all follow the same shape:
- They take in props and return JSX elements.
- They decide what to render from the registration's `type` and the node itself.
- They return JSX that renders `children` somewhere inside it, the editable content the registration wraps.
With this in mind, continue for the remaining schema types.
Register a decorator with `defineDecorator`, one per decorator name:
```tsx
const strong = defineDecorator({
type: 'strong',
render: ({children}) => {children},
})
const em = defineDecorator({
type: 'em',
render: ({children}) => {children},
})
const underline = defineDecorator({
type: 'underline',
render: ({children}) => {children},
})
const nodes = [textBlock, strong, em, underline]
```
:::note
By default, text is rendered as an inline `span` element in the editor. A decorator's render can pass `children` through unwrapped, but the registered text block render must return a block-level element, like a `
`.
:::
Mount every registration through one `NodePlugin`, inside the `EditorProvider`. Keep the `nodes` array itself at module scope, as above: a fresh array on every render would make `NodePlugin` unregister and re-register on every keystroke.
```tsx
<>
>
```
Before you can see if anything changed, you need a way to interact with the editor.
## Create a toolbar
A toolbar is a collection of UI elements for interacting with the editor. The `@portabletext/toolbar` library exposes hooks and types that allow you to create a toolbar however you like. The `@portabletext/keyboard-shortcuts` library provides drop-in shortcut access to link toolbar buttons to key commands.
Building a custom toolbar differs with each project, but in this example:
1. Add the `@portabletext/toolbar` and `@portabletext/keyboard-shortcuts` libraries to your project.
2. Create a `Toolbar` component, along with any sub-components in the same file.
3. Configure `useToolbarSchema` to access the editor schema, then loop over the schema types to create buttons for each style and decorator.
4. Enhance the schema with any icons, labels, or descriptions you want to display in the toolbar.
5. Create buttons for each schema group (styles, decorators, annotations, etc.).
6. Add the `Toolbar` to your render function inside the `EditorProvider`.
This example shows a minimal toolbar:
```tsx
// App.tsx
// ...
import {bold} from '@portabletext/keyboard-shortcuts'
import {
useDecoratorButton,
useStyleSelector,
useToolbarSchema,
type ExtendDecoratorSchemaType,
type ExtendStyleSchemaType,
type ToolbarDecoratorSchemaType,
type ToolbarStyleSchemaType,
} from '@portabletext/toolbar'
function Toolbar() {
// useToolbarSchema provides access to the PTE schema
// optionally, pass in updated schemas to override the default
const toolbarSchema = useToolbarSchema({
extendDecorator, // see declarations below
extendStyle, // see declarations below
})
return (
)
}
// Extend the schema with icons, titles, and keyboard shortcuts
const extendStyle: ExtendStyleSchemaType = (style) => {
// Apply updates to the schema, if needed
if (style.name === 'h1') {
return {
...style,
title: 'Title',
}
}
// ...repeat for each style type, or return the original style
return style
}
const extendDecorator: ExtendDecoratorSchemaType = (decorator) => {
if (decorator.name === 'strong') {
return {
...decorator,
// Optional: add a react component as an icon and unset the title
icon: () => B,
// Optional: connect to a keyboard shortcut from the keyboard-shortcuts library
shortcut: bold,
title: '',
}
}
// ...repeat for each decorator type, or return the original decorator
return decorator
}
// Create a button for each decorator type
const DecoratorButton = (props: {schemaType: ToolbarDecoratorSchemaType}) => {
const decoratorButton = useDecoratorButton(props)
return (
)
}
// One `useStyleSelector` drives all style buttons: a block has one style at
// a time, so the hook is a selector, not a per-button toggle
function StyleButtons(props: {
schemaTypes: ReadonlyArray
}) {
const styleSelector = useStyleSelector(props)
const activeStyle = styleSelector.snapshot.context.activeStyle ?? 'normal'
return props.schemaTypes.map((schemaType) => (
))
}
// ... and so on for each schema type, or create a generic button
```
The `useStyleSelector` and `useDecoratorButton` hooks give you access to the active editor. `send` lets you send events to the editor, and `snapshot` lets you read the current state of the editor.
In the next step, you'll add the toolbar to the editor.
## Bring it all together
With the registrations created and a toolbar in place, you can fully render the editor. Add the `Toolbar` inside the `EditorProvider`.
```tsx
// App.tsx
// ...
function App() {
const [value, setValue] = useState | undefined>(
undefined,
)
return (
<>
{
if (event.type === 'mutation') {
setValue(event.value)
}
}}
/>
>
)
}
// ...
```
You can now enter text and interact with the toolbar buttons to toggle the styles and decorators. These are only a small portion of the types of things you can do. Check out the [custom rendering guide](/editor/guides/custom-rendering/) and the [toolbar customization guide](/editor/guides/customize-toolbar/) for options.
## View the Portable Text data
You can preview the Portable Text from the editor by reading the state. Add the following after the `EditorProvider`:
```tsx
{JSON.stringify(value, null, 2)}
```
This displays the raw Portable Text. To customize how Portable Text renders in your apps, explore the serializers.
## Behavior API
The Behavior API lets you customize how users interact with the editor by hooking into events:
- Declaratively hook into editor **events** and define new behaviors.
- Imperatively trigger **events**.
- Derive editor **state** using **pure functions**.
- Subscribe to **emitted** editor **events**.
Learn more about [behaviors](/editor/concepts/behavior/) and how to [create your own](/editor/guides/create-behavior/).
## Next steps
# Guides
> Step-by-step guides for working with the Portable Text Editor.
Practical guides for customizing and extending the Portable Text Editor.
### [Custom rendering](/editor/guides/custom-rendering/)
Change how the editor renders and styles text. Covers render props for blocks, spans, decorators, annotations, list items, placeholders, and range decorations.
### [Migrate render props to node registrations](/editor/guides/migrate-render-props/)
Move an editor from the render props on `PortableTextEditable` to `defineX` node registrations, one kind at a time.
### [Customize the toolbar](/editor/guides/customize-toolbar/)
Build custom toolbars using `@portabletext/toolbar` hooks. Covers decorator buttons, style selectors, keyboard shortcuts, undo/redo, and reflecting editor state.
### [Create a custom behavior](/editor/guides/create-behavior/)
Add custom behaviors to the editor. Walk through defining a behavior with events, guards, and actions, then registering it with `BehaviorPlugin`.
### [Behavior recipes](/editor/guides/behavior-cheat-sheet/)
Common solutions using the Behavior API: logging, auto-closing brackets, emoji pickers, and raising events.
# Behavior recipes
> Common solutions using the Behavior API.
import {CardGrid, LinkCard} from '@astrojs/starlight/components'
import {PackageManagers} from 'starlight-package-managers'
Below are some common behavior examples. You can also find a list of core behaviors [on GitHub](https://github.com/portabletext/editor/tree/main/packages/editor/src/behaviors).
To add these to your editor, first import `defineBehavior` as well as the `BehaviorPlugin`.
```tsx
import {defineBehavior} from '@portabletext/editor/behaviors'
import {BehaviorPlugin} from '@portabletext/editor/plugins'
```
Then, register the behavior within the `EditorProvider` using the `BehaviorPlugin`.
```tsx
{/* ... */}
```
Read more about using behaviors and building your own with these guides:
## Log inserted text
Send and `effect` type action along with a `forward` action to perform side effects without altering the chain of events.
```js
const logInsertText = defineBehavior({
on: 'insert.text',
actions: [
({event}) => [
{
type: 'effect',
effect: () => {
console.log(event)
},
},
{
type: 'forward',
event,
},
],
],
})
```
The `effect` and `forward` actions also have shorthand functions:
```tsx
const logInsertText = defineBehavior({
on: 'insert.text',
actions: [
({event}) => [
effect(() => {
console.log(event)
}),
forward(event),
],
],
})
```
## Auto-close parenthesis
You can write behaviors to auto-close common paired characters. This example closes parenthesis, and then moves the cursor in between the two characters. This logic can expand to cover more sets.
```js
const autoCloseParens = defineBehavior({
on: 'insert.text',
guard: ({snapshot, event}) => {
return event.text === '('
},
actions: [
({snapshot, event}) => [
// Execute the original event that includes the '('
{type: 'execute', event},
// Execute a new insert.text event with a closing parenthesis
{
type: 'execute',
event: {
type: 'insert.text',
text: ')',
},
},
// Execute a select event to move the cursor in between the parens
{
type: 'execute',
event: {
type: 'select',
selection: {
anchor: {
path: snapshot.context.selection.anchor.path,
offset: snapshot.context.selection.anchor.offset + 1,
},
focus: {
path: snapshot.context.selection.focus.path,
offset: snapshot.context.selection.focus.offset + 1,
},
},
},
},
],
],
})
```
The `execute` action also has a shorthand function:
```tsx
const autoCloseParens = defineBehavior({
on: 'insert.text',
guard: ({snapshot, event}) => {
return event.text === '('
},
actions: [
({snapshot, event}) => [
execute(event),
// ...
],
],
})
```
## Emoji picker
An emoji picker that triggers when you insert `:` is available as a separate plugin package.

Test it out in the [Playground](https://playground.portabletext.org).
Install the package:
Use the `useEmojiPicker` hook to handle the state and logic:
```tsx
import {
createMatchEmojis,
useEmojiPicker,
} from '@portabletext/plugin-emoji-picker'
const matchEmojis = createMatchEmojis({
emojis: {
'😂': ['joy', 'laugh'],
'😹': ['joy_cat'],
},
})
function EmojiPickerComponent() {
const {keyword, matches, selectedIndex, onDismiss, onNavigateTo, onSelect} =
useEmojiPicker({matchEmojis})
// Render your emoji picker UI using these values
}
```
- [View the plugin source](https://github.com/portabletext/editor/tree/main/packages/plugin-emoji-picker).
- [View the playground editor source](https://github.com/portabletext/editor/blob/main/apps/playground/src/editor.tsx).
## Raise events
Sometimes you want to trigger an event from within an action. This sends the event back to the editor, where the editor treats it like any other event.
```tsx
const raisedUppercaseA = defineBehavior({
on: 'insert.text',
guard: ({snapshot, event}) => event.text === 'a',
actions: [
({snapshot, event}) => [
{type: 'raise', event: {type: 'insert.text', text: 'A'}},
],
],
})
```
The `raise` action also has a shorthand function:
```tsx
const raisedUppercaseA = defineBehavior({
on: 'insert.text',
guard: ({snapshot, event}) => event.text === 'a',
actions: [({snapshot, event}) => [raise({type: 'insert.text', text: 'A'})]],
})
```
:::note
Be careful when raising events, as this technique can lead to infinite loops if behaviors dispatch actions and events that trigger one another.
:::
# Create a custom behavior
> Add custom behaviors to the Portable Text Editor
import {LinkCard} from '@astrojs/starlight/components'
Behaviors add functionality to the Portable Text Editor (PTE) in a declarative way.
To learn how behaviors work, read [Behaviors](/editor/concepts/behavior/).
## Import the behavior helper
Begin by importing `defineBehavior`.
```tsx
import {defineBehavior} from '@portabletext/editor/behaviors'
```
## Define the behavior
Behaviors need three things:
- A triggering event. See the [full list of events](/editor/reference/behavior-api#behavior-event-types).
- A guard, or condition that determines if this behavior should apply.
- An action to invoke if the event and guard are met.
Here's an example behavior:
```tsx
const noLowerCaseA = defineBehavior({
on: 'insert.text',
guard: ({event}) => event.text === 'a',
actions: [() => [{type: 'execute', event: {type: 'insert.text', text: 'A'}}]],
})
```
Let's break it down:
1. It listens for the `insert.text` event. You can use any [native, synthetic or custom event](/editor/reference/behavior-api#behavior-event-types) here.
2. The guard checks if the text that triggered this event is equal to a lowercase `a`. The guard is true and the behavior will perform the actions.
3. It sends an `execute` action with an `insert.text` event to insert "A" instead of "a".
## Register the behavior
To use the behavior, add it to the `EditorProvider` using the `BehaviorPlugin`.
```tsx
import {defineBehavior} from '@portabletext/editor/behaviors'
import {BehaviorPlugin} from '@portabletext/editor/plugins'
const noLowerCaseA = defineBehavior({
on: 'insert.text',
guard: ({event}) => event.text === 'a',
actions: [() => [{type: 'execute', event: {type: 'insert.text', text: 'A'}}]],
})
// ...
{/* ... */}
```
# Custom blocks and inline objects
> Add images, code blocks, and other structured content to the Portable Text Editor.
import {LinkCard} from '@astrojs/starlight/components'
The Portable Text Editor handles text blocks (paragraphs, headings, lists) by default. To add structured content like images, code blocks, or calls to action, you define custom block types in your schema and tell the editor how to render and insert them. If your editor still renders block objects and inline objects through the deprecated `renderBlock`/`renderChild` props, see the [migration guide](/editor/guides/migrate-render-props/) to move to node registrations.
You should be familiar with the [getting started guide](/editor/getting-started/) and [custom rendering](/editor/guides/custom-rendering/) first.
## How custom blocks work
There are two kinds of custom content in Portable Text:
- **Block objects** sit alongside text blocks in the document array. An image, a code block, or a call-to-action are block objects.
- **Inline objects** sit inside text blocks, within the text flow. A stock ticker, a product reference, or a custom emoji are inline objects.
Both follow the same three-step pattern:
1. **Define** the type in your schema (`blockObjects` or `inlineObjects`)
2. **Render** it as a node registration (`defineBlockObject` or `defineInlineObject`), mounted through `NodePlugin`
3. **Insert** it via the toolbar (`useBlockObjectButton` or `useInlineObjectButton` hook)
## Adding block objects
### Step 1: define in schema
Add your block type to the `blockObjects` array in `defineSchema`. Each block object has a name and optional fields:
```tsx
import {defineSchema} from '@portabletext/editor'
const schemaDefinition = defineSchema({
// ... styles, decorators, annotations, lists
blockObjects: [{name: 'image'}, {name: 'code'}],
inlineObjects: [],
})
```
The schema tells the editor which block types are valid. The field data (image URL, code language, etc.) is stored on the block object itself.
### Step 2: render it
Register each block object type with `defineBlockObject`. The registration's `render` owns the block's wrapper element entirely:
- Spread `attributes` onto the outer element.
- Always render `children`, the engine's caret spacer that lets the browser place the cursor next to the block.
- Wrap the visible content in a `contentEditable={false}` element with `draggable={!readOnly}`. Block objects are void, and this makes them drag-movable while the outer element stays the caret anchor.
- Check for a field before using it: the registration already guarantees `node._type`, but individual fields can be absent on a partially-filled value. Fall back to `props.renderDefault(props)`, the engine's placeholder, when a field the render needs is missing.
```tsx
import {defineBlockObject} from '@portabletext/editor'
const imageBlock = defineBlockObject({
type: 'image',
render: (props) =>
typeof props.node.src === 'string' ? (
) : (
props.renderDefault(props)
),
})
```
Mount registrations through `NodePlugin`, alongside a `defineTextBlock` registration for your text blocks (a bare wrapper is enough if you don't customize them further):
```tsx
import {defineTextBlock} from '@portabletext/editor'
import {NodePlugin} from '@portabletext/editor/plugins'
const textBlock = defineTextBlock({
type: 'block',
render: ({attributes, children}) =>
{children}
,
})
const nodes = [textBlock, imageBlock, codeBlock]
;
```
:::note
A registration claims its type entirely: register `type: '*'` instead of a specific name to catch every block object type that has no more specific registration. A block object type with no registration at all, specific or `'*'`, gets a generic placeholder rendering instead of your custom look.
:::
### Step 3: insert via toolbar
Use the `useBlockObjectButton` hook from `@portabletext/toolbar` to create an insert button. The hook follows the same pattern as `useDecoratorButton` and `useStyleSelector`:
```tsx
import {
useBlockObjectButton,
useToolbarSchema,
type ExtendBlockObjectSchemaType,
type ToolbarBlockObjectSchemaType,
} from '@portabletext/toolbar'
// Extend the schema to add icons and titles for the toolbar
const extendBlockObject: ExtendBlockObjectSchemaType = (blockObject) => {
if (blockObject.name === 'image') {
return {...blockObject, title: 'Image', icon: () => 🖼}
}
if (blockObject.name === 'code') {
return {...blockObject, title: 'Code', icon: () => {'>'}}
}
return blockObject
}
function Toolbar() {
const toolbarSchema = useToolbarSchema({extendBlockObject})
return (
)
}
function BlockObjectButton(props: {schemaType: ToolbarBlockObjectSchemaType}) {
const blockObjectButton = useBlockObjectButton(props)
return (
)
}
```
Clicking the button moves the hook into its `showing dialog` state. Render the dialog for that state, and send `insert` from the dialog's submit handler:
```tsx
import {useState} from 'react'
function ImageButton(props: {schemaType: ToolbarBlockObjectSchemaType}) {
const blockObjectButton = useBlockObjectButton(props)
const [imageUrl, setImageUrl] = useState('')
return (
<>
{blockObjectButton.snapshot.matches({enabled: 'showing dialog'}) ? (
) : null}
>
)
}
```
For a block type that needs no user input at all, skip the dialog states and insert straight from `useEditor`:
```tsx
import {useEditor} from '@portabletext/editor'
function InsertButton(props: {schemaType: ToolbarBlockObjectSchemaType}) {
const editor = useEditor()
return (
)
}
```
## Adding inline objects
Inline objects work the same way as block objects, but they appear inside text blocks rather than alongside them.
### Step 1: define in schema
```tsx
const schemaDefinition = defineSchema({
// ... styles, decorators, annotations, lists, blockObjects
inlineObjects: [{name: 'stock-ticker'}],
})
```
### Step 2: render it
`defineInlineObject` follows the same shape as `defineBlockObject`, with two differences. Inline objects need no `contentEditable={false}` on the visible content: the engine's outer attributes already carry non-editability, and your content inherits it. They do need the visible content wrapped in a `draggable={!readOnly}`, `display: inline-block` element, which makes the object drag-movable and keeps its text unselectable (a draggable element starts a drag instead of a text selection).
```tsx
import {defineInlineObject} from '@portabletext/editor'
const stockTicker = defineInlineObject({
type: 'stock-ticker',
render: (props) =>
typeof props.node.symbol === 'string' ? (
{props.children}
📈 {props.node.symbol}
{typeof props.node.exchange === 'string' ? (
{props.node.exchange}
) : null}
) : (
props.renderDefault(props)
),
})
```
Add it to the same `NodePlugin`:
```tsx
const nodes = [textBlock, imageBlock, codeBlock, stockTicker]
;
```
### Step 3: insert via toolbar
Use `useInlineObjectButton`, which works identically to `useBlockObjectButton`:
```tsx
import {
useInlineObjectButton,
type ExtendInlineObjectSchemaType,
type ToolbarInlineObjectSchemaType,
} from '@portabletext/toolbar'
const extendInlineObject: ExtendInlineObjectSchemaType = (inlineObject) => {
if (inlineObject.name === 'stock-ticker') {
return {...inlineObject, title: 'Stock', icon: () => 📈}
}
return inlineObject
}
function InlineObjectButton(props: {
schemaType: ToolbarInlineObjectSchemaType
}) {
const inlineObjectButton = useInlineObjectButton(props)
return (
)
}
```
Add the inline object buttons to your toolbar alongside the block object buttons:
```tsx
function Toolbar() {
const toolbarSchema = useToolbarSchema({
extendBlockObject,
extendInlineObject,
})
return (
)
}
```
## The Portable Text output
When a user inserts a block object, the editor produces a block in the Portable Text array with the custom `_type`:
```json
[
{
"_type": "block",
"_key": "abc123",
"style": "normal",
"children": [{"_type": "span", "text": "Here is a photo:"}],
"markDefs": []
},
{
"_type": "image",
"_key": "def456",
"src": "https://example.com/photo.jpg",
"alt": "A mountain landscape"
},
{
"_type": "block",
"_key": "ghi789",
"style": "normal",
"children": [
{"_type": "span", "text": "The current price of "},
{
"_type": "stock-ticker",
"_key": "jkl012",
"symbol": "AAPL",
"exchange": "NASDAQ"
},
{"_type": "span", "text": " is rising."}
],
"markDefs": []
}
]
```
The image block sits between text blocks. The stock ticker sits inside a text block's `children` array. Both carry structured data that your rendering serializers can use.
## Next steps
# Customize editor rendering
> Change the way the editor renders and styles text.
Marks (decorators and annotations) render through node registrations: `defineDecorator` and `defineAnnotation`, mounted with `NodePlugin` alongside the editor's other registrations. [Rendering](/editor/concepts/rendering/) covers the model every registration shares: markup ownership, dispatch precedence, and `renderDefault`. [Containers](/editor/concepts/containers/) covers positional overrides, rendering a mark differently only inside one part of the document.
`renderPlaceholder` and `rangeDecorations`, the remaining rendering props without a registration equivalent, stay on ``; this guide documents them below.
The `renderDecorator`, `renderAnnotation`, `renderBlock`, `renderChild`, `renderStyle`, and `renderListItem` props are removed in this major; the [migration guide](/editor/guides/migrate-render-props/) walks through moving to registrations. None of these choices affect the Portable Text output: they only change how the editor itself renders content.
## Decorators
Register one `defineDecorator` per decorator name. `render` receives the styled `children` to wrap:
```tsx
import {defineDecorator} from '@portabletext/editor'
const strong = defineDecorator({
type: 'strong',
render: ({children}) => {children},
})
const em = defineDecorator({
type: 'em',
render: ({children}) => {children},
})
const underline = defineDecorator({
type: 'underline',
render: ({children}) => {children},
})
```
Or keep one switching function with `type: '*'`, which matches any decorator that has no more specific registration; see [dispatch precedence](/editor/concepts/rendering/#dispatch-precedence) for how it ranks against an exact `type` match:
```tsx
const decorator = defineDecorator({
type: '*',
render: ({children, decorator}) => {
if (decorator === 'strong') {
return {children}
}
if (decorator === 'em') {
return {children}
}
if (decorator === 'underline') {
return {children}
}
return <>{children}>
},
})
```
## Annotations
Register `defineAnnotation` for a markDef `_type`. `render` receives the markDef object as `annotation`:
```tsx
import {defineAnnotation} from '@portabletext/editor'
const link = defineAnnotation({
type: 'link',
render: ({annotation, children}) =>
typeof annotation.href === 'string' ? (
{children}
) : (
children
),
})
```
`render` is a plain function call, not a component, so hooks inside it violate the Rules of Hooks. When a render needs hooks, for example to open a tooltip on the annotation, return a component instead:
```tsx
import {useState} from 'react'
import type {AnnotationRenderProps} from '@portabletext/editor'
function LinkSpan(props: AnnotationRenderProps) {
const [hovered, setHovered] = useState(false)
const href =
typeof props.annotation.href === 'string' ? props.annotation.href : ''
return (
setHovered(true)}
onMouseLeave={() => setHovered(false)}
style={{textDecoration: 'underline'}}
>
{props.children}
{hovered ? {href} : null}
)
}
const link = defineAnnotation({
type: 'link',
render: (props) => ,
})
```
## Mount the registrations
Marks join the same `nodes` array as your other registrations, mounted through one `NodePlugin`: see [Register a node](/editor/concepts/rendering/#register-a-node) on the Rendering page for the full example.
## Lists
Lists are a bit unique. A list in Portable Text is flat: a run of sibling text blocks carrying `listItem` and `level`, with no wrapper node. ([Containers](/editor/concepts/containers/) nest blocks through object fields, but lists stay flat.) Visual nesting comes from CSS, and list numbering comes from [`@portabletext/plugin-list-index`](https://github.com/portabletext/editor/tree/main/packages/plugin-list-index). We suggest [including this example CSS](https://github.com/portabletext/editor/blob/main/examples/basic/src/editor.css) or similar to manage list rendering.
## Placeholder text
Use `renderPlaceholder` to display custom placeholder text when the editor is empty:
```tsx
Start typing...}
// ... other props
/>
```
## Range decorations
Use `rangeDecorations` to highlight specific ranges of text. This is useful for features like search highlighting, comments, or collaborative cursors:
```tsx
import type {RangeDecoration} from '@portabletext/editor'
const decorations: RangeDecoration[] = [
{
selection: {
anchor: {path: [{_key: 'block1'}, 'children', {_key: 'span1'}], offset: 0},
focus: {path: [{_key: 'block1'}, 'children', {_key: 'span1'}], offset: 5},
},
component: ({children}) => (
{children}
),
},
]
```
You can apply styles, libraries like Tailwind, or use custom react components within the rendering functions.
### Following a range across edits
Edits can move, shrink, or invalidate a decorated range: typing before it shifts its offsets, and deleting it removes it entirely. Pass `onMoved` on a `RangeDecoration` to keep your own state in sync instead of recomputing the selection from scratch:
```tsx
import type {
EditorSelection,
RangeDecoration,
RangeDecorationOnMovedDetails,
} from '@portabletext/editor'
import {useState} from 'react'
function Highlight() {
const [highlightSelection, setHighlightSelection] = useState(
{
anchor: {
path: [{_key: 'block1'}, 'children', {_key: 'span1'}],
offset: 0,
},
focus: {path: [{_key: 'block1'}, 'children', {_key: 'span1'}], offset: 5},
},
)
const onMoved = (details: RangeDecorationOnMovedDetails) => {
// `newSelection` is `null` when the edit removed the decorated range.
setHighlightSelection(details.newSelection)
}
const decorations: RangeDecoration[] = [
{
selection: highlightSelection,
component: ({children}) => (
{children}
),
onMoved,
},
]
return (
)
}
```
# Customize the toolbar
> Common patterns and techniques for creating custom toolbars for the editor.
import {PackageManagers} from 'starlight-package-managers'
The [getting started guide](/editor/getting-started/) introduces the basics of setting up toolbar components. This guide provides some extra context, best practices, and patterns to get you started.
## Render the toolbar inside the provider
You must render any toolbars within `EditorProvider`, as any toolbar actions require access to the instance of the editor. There are two ways to do this:
### The `@portabletext/toolbar` hooks
The `@portabletext/toolbar` library provides a variety of hooks that allow you to dispatch events and view a snapshot of the editor state.
Each hook accepts an individual schema item and returns a `send` method and a `snapshot`. The most common pattern is to `send`, or dispatch, events, and `snapshot.matches` state, like enabled/disabled.
For example, a button can use `useDecoratorButton` to create interactive buttons for decorators. The hook accepts details about the decorator, provided by the `useToolbarSchema` hook.
```tsx
import {
useDecoratorButton,
useToolbarSchema,
type ToolbarDecoratorSchemaType,
} from '@portabletext/toolbar'
const DecoratorButton = (props: {schemaType: ToolbarDecoratorSchemaType}) => {
const decoratorButton = useDecoratorButton(props)
return (
)
}
function ToolbarPlugin() {
const toolbarSchema = useToolbarSchema()
return (