---
title: "Turn Into Dropdown"
description: "Block transformation dropdown for converting between different content types like headings, lists, and blockquotes. More in the docs."
canonical_url: "https://tiptap.dev/docs/ui-components/components/turn-into-dropdown"
---

# Turn Into Dropdown

Block transformation dropdown for converting between different content types like headings, lists, and blockquotes. More in the docs.

A fully accessible block transformation dropdown for Tiptap editors. Convert between different content types like headings, paragraphs, lists, blockquotes, and code blocks with an intuitive dropdown interface.

> **Interactive demo:** [turn into dropdown](https://template.tiptap.dev/preview/tiptap-ui/turn-into-dropdown)

## Installation

Add the component via the Tiptap CLI:

```bash
npx @tiptap/cli@latest add turn-into-dropdown
```

## Components

### `<TurnIntoDropdown />`

A comprehensive dropdown component for transforming block types in a Tiptap editor.

#### Usage

```tsx
import { EditorContent, EditorContext, useEditor } from '@tiptap/react'
import { StarterKit } from '@tiptap/starter-kit'
import { TurnIntoDropdown } from '@/components/tiptap-ui/turn-into-dropdown'

import '@/components/tiptap-node/paragraph-node/paragraph-node.scss'
import '@/components/tiptap-node/heading-node/heading-node.scss'
import '@/components/tiptap-node/list-node/list-node.scss'
import '@/components/tiptap-node/blockquote-node/blockquote-node.scss'
import '@/components/tiptap-node/code-block-node/code-block-node.scss'

export default function MyEditor() {
  const editor = useEditor({
    immediatelyRender: false,
    extensions: [StarterKit],
    content: `
      <h1>Document Title</h1>
      <p>Welcome to the rich text editor. You can transform this paragraph into different block types.</p>
      <ul>
        <li>Transform any block element</li>
        <li>Choose from multiple content types</li>
        <li>Maintain content while changing structure</li>
      </ul>
    `,
  })

  return (
    <EditorContext.Provider value={{ editor }}>
      <div className="toolbar">
        <TurnIntoDropdown
          editor={editor}
          hideWhenUnavailable={false}
          blockTypes={['paragraph', 'heading', 'bulletList', 'orderedList', 'blockquote']}
          portal={false}
          useCardLayout={true}
          onOpenChange={(isOpen) => console.log('Dropdown toggled:', isOpen)}
        />
      </div>

      <EditorContent editor={editor} role="presentation" />
    </EditorContext.Provider>
  )
}
```

#### Props

| Name                  | Type                        | Default             | Description                                          |
| --------------------- | --------------------------- | ------------------- | ---------------------------------------------------- |
| `editor`              | `Editor \| null`            | `undefined`         | The Tiptap editor instance                           |
| `hideWhenUnavailable` | `boolean`                   | `false`             | Hides dropdown when block transformation unavailable |
| `blockTypes`          | `string[]`                  | All supported types | Which block types to show in the dropdown            |
| `portal`              | `boolean`                   | `false`             | Whether to render dropdown menu in a portal          |
| `useCardLayout`       | `boolean`                   | `true`              | Whether to use card layout for dropdown content      |
| `onOpenChange`        | `(isOpen: boolean) => void` | `undefined`         | Callback fired when dropdown state changes           |

### `<TurnIntoDropdownContent />`

The dropdown content component that renders the available block type options.

#### Usage

```tsx
import { TurnIntoDropdownContent } from '@/components/tiptap-ui/turn-into-dropdown'

function CustomDropdownContent() {
  return (
    <TurnIntoDropdownContent
      blockTypes={['paragraph', 'heading', 'bulletList']}
      useCardLayout={false}
    />
  )
}
```

#### Props

| Name            | Type       | Default | Description                              |
| --------------- | ---------- | ------- | ---------------------------------------- |
| `blockTypes`    | `string[]` | All     | Which block types to show                |
| `useCardLayout` | `boolean`  | `true`  | Whether to wrap content in a card layout |

## Hooks

### `useTurnIntoDropdown()`

A custom hook to build your own turn into dropdown with full control over rendering and behavior.

#### Usage

```tsx
import { useTurnIntoDropdown } from '@/components/tiptap-ui/turn-into-dropdown'

function MyTurnIntoDropdown() {
  const {
    isVisible,
    canToggle,
    isOpen,
    activeBlockType,
    handleOpenChange,
    filteredOptions,
    label,
    Icon,
  } = useTurnIntoDropdown({
    editor: myEditor,
    hideWhenUnavailable: true,
    blockTypes: ['paragraph', 'heading', 'bulletList'],
    onOpenChange: (isOpen) => console.log('Dropdown toggled:', isOpen),
  })

  if (!isVisible) return null

  return (
    <DropdownMenu open={isOpen} onOpenChange={handleOpenChange}>
      <DropdownMenuTrigger asChild>
        <button disabled={!canToggle} aria-label={label}>
          <span>{activeBlockType?.label || 'Text'}</span>
          <Icon />
        </button>
      </DropdownMenuTrigger>
      <DropdownMenuContent>
        {filteredOptions.map((option) => (
          <DropdownMenuItem key={option.type}>{option.label}</DropdownMenuItem>
        ))}
      </DropdownMenuContent>
    </DropdownMenu>
  )
}
```

#### Props

| Name                  | Type                        | Default     | Description                                          |
| --------------------- | --------------------------- | ----------- | ---------------------------------------------------- |
| `editor`              | `Editor \| null`            | `undefined` | The Tiptap editor instance                           |
| `hideWhenUnavailable` | `boolean`                   | `false`     | Hides dropdown when block transformation unavailable |
| `blockTypes`          | `string[]`                  | All types   | Which block types to show in the dropdown            |
| `onOpenChange`        | `(isOpen: boolean) => void` | `undefined` | Callback fired when dropdown state changes           |

#### Return Values

| Name               | Type                      | Description                                   |
| ------------------ | ------------------------- | --------------------------------------------- |
| `isVisible`        | `boolean`                 | Whether the dropdown should be rendered       |
| `canToggle`        | `boolean`                 | If block transformation is currently allowed  |
| `isOpen`           | `boolean`                 | Whether the dropdown is currently open        |
| `setIsOpen`        | `(open: boolean) => void` | Function to set dropdown open state           |
| `activeBlockType`  | `BlockTypeOption`         | Currently active block type information       |
| `handleOpenChange` | `(open: boolean) => void` | Function to handle dropdown open/close        |
| `filteredOptions`  | `BlockTypeOption[]`       | Filtered list of available block type options |
| `label`            | `string`                  | Accessible label text for the dropdown        |
| `Icon`             | `React.FC`                | Icon component for the dropdown trigger       |

## Block Types

The Turn Into Dropdown supports transformation between various block types:

### Supported Block Types

- **paragraph**: Regular text paragraphs
- **heading**: Headings (levels 1, 2, and 3)
- **bulletList**: Bulleted (unordered) lists
- **orderedList**: Numbered (ordered) lists
- **taskList**: To-do lists with checkboxes
- **blockquote**: Quote blocks for highlighted text
- **codeBlock**: Code blocks with syntax highlighting

### Block Type Options

Each block type includes:

```tsx
interface BlockTypeOption {
  type: string // The node type name
  label: string // Display label
  level?: number // For headings (1, 2, 3)
  isActive: (editor: Editor) => boolean // Function to check if active
}
```

## Utilities

### `canTurnInto(editor, allowedBlockTypes?)`

Checks if block transformation can be performed in the current editor state.

```tsx
import { canTurnInto } from '@/components/tiptap-ui/turn-into-dropdown'

const canTransform = canTurnInto(editor, ['paragraph', 'heading'])
if (canTransform) {
  console.log('Block transformation is available')
}
```

#### Parameters

| Name                | Type             | Description                           |
| ------------------- | ---------------- | ------------------------------------- |
| `editor`            | `Editor \| null` | The Tiptap editor instance            |
| `allowedBlockTypes` | `string[]`       | Optional array of allowed block types |

#### Returns

`boolean` - Whether block transformation can be performed.

### `getFilteredBlockTypeOptions(blockTypes?)`

Gets filtered block type options based on available types.

```tsx
import { getFilteredBlockTypeOptions } from '@/components/tiptap-ui/turn-into-dropdown'

const options = getFilteredBlockTypeOptions(['paragraph', 'heading', 'bulletList'])
console.log(
  'Available options:',
  options.map((o) => o.label),
)
```

#### Parameters

| Name         | Type       | Description                             |
| ------------ | ---------- | --------------------------------------- |
| `blockTypes` | `string[]` | Optional array of block types to filter |

#### Returns

`BlockTypeOption[]` - Filtered array of block type options.

### `getActiveBlockType(editor, blockTypes?)`

Gets the currently active block type from the available options.

```tsx
import { getActiveBlockType } from '@/components/tiptap-ui/turn-into-dropdown'

const activeType = getActiveBlockType(editor, ['paragraph', 'heading'])
console.log('Current block type:', activeType?.label)
```

#### Parameters

| Name         | Type             | Description                           |
| ------------ | ---------------- | ------------------------------------- |
| `editor`     | `Editor \| null` | The Tiptap editor instance            |
| `blockTypes` | `string[]`       | Optional array of allowed block types |

#### Returns

`BlockTypeOption` - Currently active block type option.

### `shouldShowTurnInto(params)`

Determines if the turn into dropdown should be visible based on editor state.

```tsx
import { shouldShowTurnInto } from '@/components/tiptap-ui/turn-into-dropdown'

const shouldShow = shouldShowTurnInto({
  editor: myEditor,
  hideWhenUnavailable: true,
  blockTypes: ['paragraph', 'heading'],
})
```

#### Parameters

| Name                         | Type             | Description                                     |
| ---------------------------- | ---------------- | ----------------------------------------------- |
| `params.editor`              | `Editor \| null` | The Tiptap editor instance                      |
| `params.hideWhenUnavailable` | `boolean`        | Whether to hide when transformation unavailable |
| `params.blockTypes`          | `string[]`       | Optional array of allowed block types           |

#### Returns

`boolean` - Whether the dropdown should be shown.

## Behavior and Constraints

### Selection Requirements

The Turn Into Dropdown works with different selection types:

- **Text Selection**: Works within block elements
- **Node Selection**: Works when entire blocks are selected
- **Empty Selection**: Works when cursor is placed within a block

### Supported Transformations

The component intelligently handles transformations between different block types:

- **Content Preservation**: Text content is maintained during transformation
- **Structure Changes**: Block structure changes while preserving inline formatting
- **List Handling**: Supports conversion between different list types
- **Heading Levels**: Allows selection of different heading levels

### Editor State Dependencies

- **Editable Editor**: Only works when the editor is in editable mode
- **Valid Block Context**: Requires cursor to be within a transformable block
- **Extension Availability**: Requires relevant extensions (StarterKit covers most cases)

## Integration Examples

### With Custom Block Types

```tsx
function EditorWithCustomBlocks() {
  const customBlockTypes = ['paragraph', 'heading', 'bulletList', 'blockquote']

  return <TurnIntoDropdown blockTypes={customBlockTypes} hideWhenUnavailable={true} />
}
```

### With Portal Rendering

```tsx
function FloatingTurnIntoDropdown() {
  return (
    <TurnIntoDropdown
      portal={true} // Renders in a portal for better z-index control
      useCardLayout={false} // Simplified layout
      hideWhenUnavailable={true}
    />
  )
}
```

### With State Tracking

```tsx
function EditorWithStateTracking() {
  const [currentBlockType, setCurrentBlockType] = useState<string>('paragraph')

  const handleOpenChange = (isOpen: boolean) => {
    if (!isOpen) {
      // Update tracking when dropdown closes
      const activeType = getActiveBlockType(editor)
      setCurrentBlockType(activeType?.type || 'paragraph')
    }
  }

  return (
    <div>
      <p>Current block type: {currentBlockType}</p>
      <TurnIntoDropdown onOpenChange={handleOpenChange} />
    </div>
  )
}
```

### Custom Dropdown Implementation

```tsx
function CustomTurnIntoDropdown() {
  const { isVisible, canToggle, activeBlockType, filteredOptions, handleOpenChange } =
    useTurnIntoDropdown({
      hideWhenUnavailable: true,
      blockTypes: ['paragraph', 'heading', 'bulletList', 'orderedList'],
    })

  if (!isVisible) return null

  return (
    <div className="custom-turn-into">
      <select
        disabled={!canToggle}
        value={activeBlockType?.type || 'paragraph'}
        onChange={(e) => {
          const option = filteredOptions.find((opt) => opt.type === e.target.value)
          if (option?.onClick) {
            option.onClick()
          }
        }}
      >
        {filteredOptions.map((option) => (
          <option key={option.type} value={option.type}>
            {option.label}
          </option>
        ))}
      </select>
    </div>
  )
}
```

## Requirements

### Dependencies

- `@tiptap/react` - Core Tiptap React integration

### Extensions

Any extensions that provide the block types you want to support:

- `@tiptap/starter-kit` - Provides most common block types
- Individual extensions for specific block types

### Referenced Components

- `use-tiptap-editor` (hook)
- `text-button`, `heading-button`, `list-button`, `blockquote-button`, `code-block-button` (ui components)
- `button`, `button-group` (primitives)
- `dropdown-menu` (primitive)
- `card` (primitive)
- `chevron-down-icon` (icon)
