mirror of
https://github.com/resend/react-email.git
synced 2026-09-14 14:18:02 +08:00
154 lines
4.5 KiB
Plaintext
154 lines
4.5 KiB
Plaintext
---
|
|
title: "Bubble Menu"
|
|
sidebarTitle: "Bubble Menu"
|
|
description: "Add floating formatting toolbars that appear on text selection."
|
|
icon: "message-lines"
|
|
---
|
|
|
|
## Quick start
|
|
|
|
Add `BubbleMenu` as a child of `EditorProvider` to get a fully-featured formatting toolbar.
|
|
|
|
```tsx
|
|
import { StarterKit } from '@react-email/editor/extensions';
|
|
import { BubbleMenu } from '@react-email/editor/ui';
|
|
import { EditorProvider } from '@tiptap/react';
|
|
import '@react-email/editor/themes/default.css';
|
|
|
|
const extensions = [StarterKit];
|
|
|
|
export function MyEditor() {
|
|
return (
|
|
<EditorProvider extensions={extensions} content={content}>
|
|
<BubbleMenu />
|
|
</EditorProvider>
|
|
);
|
|
}
|
|
```
|
|
|
|
Select text to see the toolbar with formatting, alignment, node type selection, and link controls.
|
|
|
|
When `BubbleMenu` has no children, it renders the default text formatting toolbar automatically.
|
|
|
|
<Tip>
|
|
Even though you can [compose BubbleMenu from
|
|
primitives](#composing-from-primitives) and style it that way, the default
|
|
can also be styled using <br/> [CSS variables and `data-re-*` selectors](/editor/features/styling#bubble-menu).
|
|
</Tip>
|
|
|
|
## Hiding on specific nodes or marks
|
|
|
|
Prevent the bubble menu from appearing on certain node types or when certain marks are active.
|
|
|
|
```tsx
|
|
<BubbleMenu
|
|
hideWhenActiveNodes={['codeBlock', 'button']}
|
|
hideWhenActiveMarks={['link']}
|
|
/>
|
|
```
|
|
|
|
This is useful when combining the text bubble menu with contextual menus for links, images, or buttons -- each gets its own menu via `BubbleMenu`.
|
|
|
|
```tsx
|
|
import { BubbleMenu, bubbleMenuTriggers } from '@react-email/editor/ui';
|
|
import { PluginKey } from '@tiptap/pm/state';
|
|
|
|
const linkPluginKey = new PluginKey('linkBubbleMenu');
|
|
|
|
<>
|
|
{/* Hide text bubble menu on links and buttons -- their own menus handle those */}
|
|
<BubbleMenu hideWhenActiveNodes={['button']} hideWhenActiveMarks={['link']} />
|
|
|
|
<BubbleMenu
|
|
trigger={bubbleMenuTriggers.nodeWithoutSelection('link')}
|
|
pluginKey={linkPluginKey}
|
|
>
|
|
<BubbleMenu.LinkToolbar>
|
|
<BubbleMenu.LinkEditLink />
|
|
<BubbleMenu.LinkOpenLink />
|
|
<BubbleMenu.LinkUnlink />
|
|
</BubbleMenu.LinkToolbar>
|
|
</BubbleMenu>
|
|
</>
|
|
```
|
|
|
|
## Composing from primitives
|
|
|
|
For full control, build a custom bubble menu using the compound component API.
|
|
|
|
```tsx
|
|
import { StarterKit } from '@react-email/editor/extensions';
|
|
import { BubbleMenu } from '@react-email/editor/ui';
|
|
import { EditorProvider } from '@tiptap/react';
|
|
|
|
export function MyEditor() {
|
|
return (
|
|
<EditorProvider extensions={[StarterKit]} content={content}>
|
|
<BubbleMenu>
|
|
<BubbleMenu.ItemGroup>
|
|
<BubbleMenu.Bold />
|
|
<BubbleMenu.Italic />
|
|
<BubbleMenu.Underline />
|
|
</BubbleMenu.ItemGroup>
|
|
<BubbleMenu.ItemGroup>
|
|
<BubbleMenu.AlignLeft />
|
|
<BubbleMenu.AlignCenter />
|
|
<BubbleMenu.AlignRight />
|
|
</BubbleMenu.ItemGroup>
|
|
</BubbleMenu>
|
|
</EditorProvider>
|
|
);
|
|
}
|
|
```
|
|
|
|
`BubbleMenu` wraps everything, `BubbleMenu.ItemGroup` creates visual groupings,
|
|
and individual items render the toggle buttons.
|
|
|
|
## Available items
|
|
|
|
| Component | Description |
|
|
| -- | -- |
|
|
| `BubbleMenu.Bold` | Bold toggle |
|
|
| `BubbleMenu.Italic` | Italic toggle |
|
|
| `BubbleMenu.Underline` | Underline toggle |
|
|
| `BubbleMenu.Strike` | Strikethrough toggle |
|
|
| `BubbleMenu.Code` | Inline code toggle |
|
|
| `BubbleMenu.Uppercase` | Uppercase toggle |
|
|
| `BubbleMenu.AlignLeft` | Left alignment |
|
|
| `BubbleMenu.AlignCenter` | Center alignment |
|
|
| `BubbleMenu.AlignRight` | Right alignment |
|
|
| `BubbleMenu.NodeSelector` | Block type dropdown (paragraph, h1-h3, etc.) |
|
|
| `BubbleMenu.LinkSelector` | Link add/edit popover |
|
|
| `BubbleMenu.Separator` | Visual separator between groups |
|
|
|
|
## Placement and offset
|
|
|
|
Control where the bubble menu appears relative to the selection.
|
|
|
|
```tsx
|
|
<BubbleMenu placement="top" offset={12}>
|
|
{/* items */}
|
|
</BubbleMenu>
|
|
```
|
|
|
|
<ResponseField name="placement" type="'top' | 'bottom'" default="'bottom'">
|
|
Whether the menu appears above or below the selection.
|
|
</ResponseField>
|
|
|
|
<ResponseField name="offset" type="number" default="8">
|
|
Distance from the selection in pixels.
|
|
</ResponseField>
|
|
|
|
## Examples
|
|
|
|
See bubble menus in action with runnable examples:
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="Bubble Menu" icon="code" href="https://react.email/editor/examples/bubble-menu">
|
|
Default bubble menu with text selection.
|
|
</Card>
|
|
<Card title="Custom Bubble Menu" icon="code" href="https://react.email/editor/examples/custom-bubble-menu">
|
|
Composing a custom menu from primitives.
|
|
</Card>
|
|
</CardGroup>
|