Block Selection

PreviousNext

Documentation for Block Selection

Docs
platefile

Preview

Loading preview…
../../docs/(plugins)/(functionality)/block-selection.mdx
---
title: Block Selection
docs:
  - route: /docs/components/block-selection
    title: Block Selection
---

<ComponentPreview name="block-selection-demo" />

<PackageInfo>

The Block Selection feature allows users to select and manipulate entire text blocks, as opposed to individual words or characters.

## Features

- Select entire blocks with a single action.
- Multi-block selection using mouse drag or keyboard shortcuts.
- Copy, cut, and delete operations on selected blocks.
- Keyboard shortcuts for quick selection:
  - `Cmd+A`: Select all blocks.
  - Arrow keys: Select the block above or below.
- Customizable styling for selected blocks.

</PackageInfo>

## Kit Usage

<Steps>

### Installation

The fastest way to add Block Selection is with the `BlockSelectionKit`, which includes the pre-configured `BlockSelectionPlugin` and the [`BlockSelection`](/docs/components/block-selection) UI component.

<ComponentSource name="block-selection-kit" />

- [`BlockSelection`](/docs/components/block-selection): Renders the selection rectangle around selected blocks.

### Add Kit

The `BlockSelectionKit` enables the context menu by default and provides a default `isSelectable` logic to exclude common non-selectable blocks like code lines and table cells.

```tsx
import { createPlateEditor } from 'platejs/react';
import { BlockSelectionKit } from '@/components/editor/plugins/block-selection-kit';

const editor = createPlateEditor({
  plugins: [
    // ...otherPlugins,
    ...BlockSelectionKit,
  ],
});
```

</Steps>

## Manual Usage

<Steps>

### Installation

```bash
npm install @platejs/selection
```

### Add Plugin

```tsx
import { BlockSelectionPlugin } from '@platejs/selection/react';
import { createPlateEditor } from 'platejs/react';

const editor = createPlateEditor({
  plugins: [
    // ...otherPlugins,
    BlockSelectionPlugin,
  ],
});
```

Put this plugin before any other plugins overriding `selectAll``Cmd+A` (code block, table, column, etc.) to avoid any conflicts.

#### Excluding Blocks from Selection

You can control which blocks are selectable using `options.isSelectable`. This function receives an element and its path, and should return `true` if the block is selectable.

For example, to exclude code lines, columns, and table cells:

```tsx
import { BlockSelectionPlugin } from '@platejs/selection/react';

BlockSelectionPlugin.configure({
  options: {
    isSelectable: (element, path) => {
      if (['code_line', 'column', 'td'].includes(element.type)) {
        return false;
      }
      // Exclude blocks inside table rows
      if (editor.api.block({ above: true, at: path, match: { type: 'tr' } })) {
        return false;
      }
      return true;
    },
  },
});
```

#### Customizing Scroll Behavior

If your editor is inside a scrollable container, you may need to configure the selection area's boundaries and scroll speed.

1.  Add an `id` to your scroll container, e.g., `id={editor.meta.uid}`.
2.  Set `position: relative` on the container.
3.  Use the `areaOptions` to configure the boundaries and scrolling behavior.

```ts
BlockSelectionPlugin.configure({
  options: {
    areaOptions: {
      boundaries: `#${editor.meta.uid}`,
      container: `#${editor.meta.uid}`,
      behaviour: {
        scrolling: {
          // Recommended speed, close to native
          speedDivider: 0.8,
        },
        // Threshold to start selection area
        startThreshold: 4,
      },
    },
  },
});
```

#### Full Page Selection

You can enable block selection for elements outside the `<Editor />` component by adding the `data-plate-selectable` attribute.

```tsx
<Cover data-plate-selectable />
<Sidebar data-plate-selectable />
```

To prevent unselecting blocks when clicking on certain elements (e.g., a toolbar button), add the `data-plate-prevent-unselect` attribute.

```tsx
<YourToolbarButton data-plate-prevent-unselect />
```

To reset the selection when clicking outside selectable areas, you can use a click handler or call the API directly:

```tsx
// 1. Direct API call
editor.api.blockSelection.deselect();

// 2. Click outside handler
const handleClickOutside = (event: MouseEvent) => {
  if (!(event.target as HTMLElement).closest('[data-plate-selectable]')) {
    editor.api.blockSelection.deselect();
  }
};
```

</Steps>

## Styling

### Selection Area

Style the selection area by targeting the `.slate-selection-area` class, which is added to the editor container.

```css
/* Example using Tailwind CSS utility classes */
'[&_.slate-selection-area]:border [&_.slate-selection-area]:border-primary [&_.slate-selection-area]:bg-primary/10'
```

### Selected Element

Use the `useBlockSelected` hook to determine if a block is selected. You can render a visual indicator, like the [`BlockSelection`](/docs/components/block-selection) component, which is designed for this purpose.

Plate UI renders this component for all selectable blocks using `render.belowRootNodes`:

```tsx
render: {
  belowRootNodes: (props) => {
    if (!props.className?.includes('slate-selectable')) return null;

    return <BlockSelection />;
  },
},
```

## Plugins

### `BlockSelectionPlugin`

Plugin for block selection functionality.

<API name="BlockSelectionPlugin">
<APIOptions>
  <APIItem name="areaOptions" type="PartialSelectionOptions" optional>
    Options for the selection area. See [SelectionJS docs](https://github.com/Simonwep/selection-js) for all available options.
    
```ts
{
  boundaries: [`#${editor.meta.uid}`],
  container: [`#${editor.meta.uid}`],
  selectables: [`#${editor.meta.uid} .slate-selectable`],
  selectionAreaClass: 'slate-selection-area',
}
```
    
  </APIItem>
  <APIItem name="enableContextMenu" type="boolean" optional>
    Enables or disables the context menu for block selection.
    - **Default:** `false`
  </APIItem>
  <APIItem name="isSelecting" type="boolean" optional>
    Indicates whether block selection is currently active.
    - **Default:** `false`
  </APIItem>
  <APIItem name="onKeyDownSelecting" type="(e: KeyboardEvent) => void" optional>
    A function to handle the keydown event when selecting.
  </APIItem>
  <APIItem name="query" type="QueryNodeOptions" optional>
    Options for querying nodes during block selection.
    - **Default:** `{ maxLevel: 1 }`
  </APIItem>
  <APIItem name="selectedIds" type="Set<string>" optional>
    A set of IDs for the currently selected blocks.
    - **Default:** `new Set()`
  </APIItem>
  <APIItem name="anchorId" type="string | null" optional>
    (Internal) The ID of the anchor block in the current selection. Used for shift-based selection.
    - **Default:** `null`
  </APIItem>
  <APIItem name="isSelectable" type="(element: TElement, path: Path) => boolean" optional>
    Function to determine if a block element is selectable.
    - **Default:** `() => true`
  </APIItem>
</APIOptions>
</API>

## API

### `api.blockSelection.add`

Adds one or more blocks to the selection.

<API name="add">
  <APIParameters>
    <APIItem name="id" type="string | string[]">
      The ID(s) of the block(s) to be selected.
    </APIItem>
  </APIParameters>
</API>

### `api.blockSelection.clear`

Resets the set of selected IDs to an empty set.

### `api.blockSelection.delete`

Removes one or more blocks from the selection.

<API name="delete">
  <APIParameters>
    <APIItem name="id" type="string | string[]">
      The ID(s) of the block(s) to remove from selection.
    </APIItem>
  </APIParameters>
</API>

### `api.blockSelection.deselect`

Deselects all blocks and sets the `isSelecting` flag to false.

### `api.blockSelection.focus`

Focuses the block selection shadow input. This input handles copy, delete, and paste events for selected blocks.

### `api.blockSelection.getNodes`

Gets the selected blocks in the editor.

<API name="getNodes">
<APIParameters>
  <APIItem name="options" type="{ selectionFallback?: boolean }" optional>
    Options for getting nodes.
  </APIItem>
</APIParameters>

<APIOptions type="object">
  <APIItem name="selectionFallback" type="boolean" optional>
    If true, and no blocks are selected by block selection, the method will use
    the editor's original selection to retrieve blocks. - **Default:** `false`
  </APIItem>
</APIOptions>

<APIReturns type="NodeEntry[]">
  Array of selected block entries.
</APIReturns>
</API>

### `api.blockSelection.has`

Checks if one or more blocks are selected.

<API name="has">
  <APIParameters>
    <APIItem name="id" type="string | string[]">
      The ID(s) of the block(s) to check.
    </APIItem>
  </APIParameters>
  <APIReturns>
    <APIItem type="boolean">Whether the block(s) are selected.</APIItem>
  </APIReturns>
</API>

### `api.blockSelection.isSelectable`

Checks if a block at a given path is selectable based on the `isSelectable` plugin option.

<API name="isSelectable">
  <APIParameters>
    <APIItem name="element" type="TElement">
      Block element to check.
    </APIItem>
    <APIItem name="path" type="Path">
      Path to the block element.
    </APIItem>
  </APIParameters>
  <APIReturns type="boolean">Whether the block is selectable.</APIReturns>
</API>

### `api.blockSelection.moveSelection`

Moves the selection up or down to the next selectable block.

When moving up:

- Gets the previous selectable block from the top-most selected block
- Sets it as the new anchor
- Clears previous selection and selects only this block
  When moving down:
- Gets the next selectable block from the bottom-most selected block
- Sets it as the new anchor
- Clears previous selection and selects only this block

<API name="moveSelection">
  <APIParameters>
    <APIItem name="direction" type="'up' | 'down'">
      Direction to move selection.
    </APIItem>
  </APIParameters>
</API>

### `api.blockSelection.selectAll`

Selects all selectable blocks in the editor.

### `api.blockSelection.set`

Sets the selection to one or more blocks, clearing any existing selection.

<API name="set">
  <APIParameters>
    <APIItem name="id" type="string | string[]">
      The ID(s) of the block(s) to be selected.
    </APIItem>
  </APIParameters>
</API>

### `api.blockSelection.shiftSelection`

Expands or shrinks the selection based on the anchor block.

For `Shift+ArrowDown`:

- If anchor is top-most: Expands down by adding block below bottom-most
- Otherwise: Shrinks from top-most (unless top-most is the anchor)
  For `Shift+ArrowUp`:
- If anchor is bottom-most: Expands up by adding block above top-most
- Otherwise: Shrinks from bottom-most (unless bottom-most is the anchor)
  The anchor block always remains selected. If no anchor is set, it defaults to:
- Bottom-most block for `Shift+ArrowUp`
- Top-most block for `Shift+ArrowDown`

<API name="shiftSelection">
  <APIParameters>
    <APIItem name="direction" type="'up' | 'down'">
      Direction to expand/shrink selection.
    </APIItem>
  </APIParameters>
</API>

## Transforms

### `tf.blockSelection.duplicate`

Duplicates the selected blocks.

### `tf.blockSelection.removeNodes`

Removes the selected nodes from the editor.

### `tf.blockSelection.select`

Selects the nodes returned by `getNodes()` in the editor and resets selected IDs.

### `tf.blockSelection.setNodes`

Sets properties on the selected nodes.

<API name="setNodes">
  <APIParameters>
    <APIItem name="props" type="Partial<NodeProps<TElement>>">
      Properties to set on selected nodes.
    </APIItem>
    <APIItem name="options" type="SetNodesOptions" optional>
      Options for setting nodes.
    </APIItem>
  </APIParameters>
</API>

### `tf.blockSelection.setTexts`

Sets text properties on the selected nodes.

<API name="setTexts">
  <APIParameters>
    <APIItem name="props" type="Partial<NodeProps<TText>>">
      Text properties to set on selected nodes.
    </APIItem>
    <APIItem name="options" type="Omit<SetNodesOptions, 'at'>" optional>
      Options for setting text nodes, excluding the 'at' property.
    </APIItem>
  </APIParameters>
</API>

## Hooks

### `useBlockSelectable`

A hook that provides props for making a block element selectable, including context menu behavior.

<API name="useBlockSelectable">
  <APIReturns type="object">
    <APIItem name="props" type="object">
      Props to be spread on the block element.
      <APISubList>
        <APISubListItem parent="props" name="className" type="string">
          Required class for selection functionality. - **Default:**
          `'slate-selectable'`
        </APISubListItem>
        <APISubListItem
          parent="props"
          name="onContextMenu"
          type="(event: React.MouseEvent) => void"
        >
          Handles right-click context menu behavior: - Opens context menu for
          selected blocks - Opens for void elements - Opens for elements with
          `data-plate-open-context-menu="true"` - Adds block to selection with
          Shift key for multi-select
        </APISubListItem>
      </APISubList>
    </APIItem>
  </APIReturns>
</API>

### `useBlockSelected`

<API name="useBlockSelected">
  <APIReturns type="boolean">Whether the context block is selected.</APIReturns>
</API>

### `useBlockSelectionNodes`

<API name="useBlockSelectionNodes">
  <APIReturns type="NodeEntry[]">Array of selected block entries.</APIReturns>
</API>

### `useBlockSelectionFragment`

<API name="useBlockSelectionFragment">
  <APIReturns type="Node[]">Array of selected block nodes.</APIReturns>
</API>

### `useBlockSelectionFragmentProp`

<API name="useBlockSelectionFragmentProp">
  <APIReturns type="Node[]">Fragment prop for selected blocks.</APIReturns>
</API>

### `useSelectionArea`

Initialize and manage selection area functionality.

Installation

npx shadcn@latest add @plate/block-selection-docs

Usage

Usage varies by registry entry. Refer to the registry docs or source files below for details.