Slate React Event Handling

PreviousNext

Editable owns the default browser event handlers for rich-text editing, including copy, paste, drop, keyboard, native input, selection, focus, and drag events.

Pass event handlers to Editable when app UI needs to run before Slate's default behavior.

Handler return values control whether Slate continues with its own handling:

  • Return true to mark the event handled and skip Slate's default handler.
  • Return false to force Slate's default handler to run.
  • Return nothing to let Slate continue unless the event is default-prevented or propagation-stopped.
import type { DragEvent, MouseEvent } from 'react'
import { Editable } from '@platejs/slate-react'
 
const MyEditor = () => {
  const onClick = (event: MouseEvent<HTMLDivElement>) => {
    trackEditorClick(event)
 
    // Slate runs its click handler unless this handler prevents default,
    // stops propagation, or returns true.
  }
 
  const onDrop = (event: DragEvent<HTMLDivElement>) => {
    if (!isAppOwnedDrop(event)) return false
 
    insertAppOwnedDrop(event)
 
    return true
  }
 
  const onDragStart = (event: DragEvent<HTMLDivElement>) => {
    annotateDragPayload(event)
 
    return false
  }
 
  return (
    <Editable
      onClick={onClick}
      onDrop={onDrop}
      onDragStart={onDragStart}
    />
  )
}
import type { DragEvent, MouseEvent } from 'react'
import { Editable } from '@platejs/slate-react'
 
const MyEditor = () => {
  const onClick = (event: MouseEvent<HTMLDivElement>) => {
    trackEditorClick(event)
 
    // Slate runs its click handler unless this handler prevents default,
    // stops propagation, or returns true.
  }
 
  const onDrop = (event: DragEvent<HTMLDivElement>) => {
    if (!isAppOwnedDrop(event)) return false
 
    insertAppOwnedDrop(event)
 
    return true
  }
 
  const onDragStart = (event: DragEvent<HTMLDivElement>) => {
    annotateDragPayload(event)
 
    return false
  }
 
  return (
    <Editable
      onClick={onClick}
      onDrop={onDrop}
      onDragStart={onDragStart}
    />
  )
}

Use onKeyDown and onDOMBeforeInput when a handler needs editor context:

<Editable
  onDOMBeforeInput={(event, { editor, inputType }) => {
    if (inputType !== 'formatBold') return false
 
    editor.update((tx) => {
      tx.marks.toggle('bold')
    })
 
    return true
  }}
  onKeyDown={(event, { editor }) => {
    if (!(event.metaKey && event.key === 'k')) return false
 
    editor.update((tx) => {
      tx.text.insert('link')
    })
 
    return true
  }}
/>
<Editable
  onDOMBeforeInput={(event, { editor, inputType }) => {
    if (inputType !== 'formatBold') return false
 
    editor.update((tx) => {
      tx.marks.toggle('bold')
    })
 
    return true
  }}
  onKeyDown={(event, { editor }) => {
    if (!(event.metaKey && event.key === 'k')) return false
 
    editor.update((tx) => {
      tx.text.insert('link')
    })
 
    return true
  }}
/>