Skip to content

Behavior Recipes

Below are some common behavior examples. You can also find a list of core behaviors on GitHub.

To add these to your editor, first import defineBehavior as well as the BehaviorPlugin.

import {defineBehavior} from '@portabletext/editor/behaviors'
import {BehaviorPlugin} from '@portabletext/editor/plugins'

Then, register the behavior within the EditorProvider using the BehaviorPlugin.

<EditorProvider
initialConfig={{
schemaDefinition,
}}
>
<BehaviorPlugin behaviors={[logInsertText]} />
{/* ... */}
</EditorProvider>

Read more about using behaviors and building your own with these guides:

Log inserted text

Send and effect type action along with an effect to perform side effects.

const logInsertText = defineBehavior({
on: 'insert.text',
actions: [
({event}) => [
{
type: 'effect',
effect: () => {
console.log(event)
},
},
],
],
})

The effect action also has a shorthand function:

const logInsertText = defineBehavior({
on: 'insert.text',
actions: [
({event}) => [
effect(() => {
console.log(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.

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:

const autoCloseParens = defineBehavior({
on: 'insert.text',
guard: ({snapshot, event}) => {
return event.text === '('
},
actions: [
({snapshot, event}) => [
execute(event),
// ...
],
],
})

Emoji Picker

Using a factory to create behaviors, a state machine, and custom components results in an emoji picker that triggers when you insert :.

Emoji picker in Portable Text Editor

Test it out in the Playground.

You can leverage the behavior by importing createEmojiPickerBehaviors from @portabletext/editor/behaviors. See the editor source above for a usage example.

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.

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:

const raisedUppercaseA = defineBehavior({
on: 'insert.text',
guard: ({snapshot, event}) => event.text === 'a',
actions: [({snapshot, event}) => [raise({type: 'insert.text', text: 'A'})]],
})