The FloatingToolbar component displays a floating toolbar when text is selected, providing quick access to text formatting options like bold, italic, and other marks.
Installation
Basic Usage
import { FloatingToolbar } from '@yoopta/ui';
import { Marks, useYooptaEditor } from '@yoopta/editor';
import { BoldIcon, ItalicIcon } from 'lucide-react';
function MyToolbar() {
const editor = useYooptaEditor();
return (
<FloatingToolbar>
<FloatingToolbar.Content>
<FloatingToolbar.Group>
<FloatingToolbar.Button
onClick={() => Marks.toggle(editor, { type: 'bold' })}
active={Marks.isActive(editor, { type: 'bold' })}
>
<BoldIcon />
</FloatingToolbar.Button>
<FloatingToolbar.Button
onClick={() => Marks.toggle(editor, { type: 'italic' })}
active={Marks.isActive(editor, { type: 'italic' })}
>
<ItalicIcon />
</FloatingToolbar.Button>
</FloatingToolbar.Group>
</FloatingToolbar.Content>
</FloatingToolbar>
);
}
Component API
The root component that tracks text selection and manages toolbar visibility.
children
ReactNode | ((api: FloatingToolbarApi) => ReactNode)
Toolbar content or render function receiving toolbar state
When true, pauses selection tracking (useful when a popover is open)
Additional CSS class name
FloatingToolbar.Content
The floating content container that renders above the selection.
Toolbar buttons and groups
Additional CSS class name
Groups related buttons together.
Additional CSS class name
Button content (usually an icon)
Whether the button is in active state
Whether the button is disabled
Additional CSS class name
Visual separator between button groups.
Additional CSS class name
Examples
import { FloatingToolbar } from '@yoopta/ui';
import { Marks, useYooptaEditor } from '@yoopta/editor';
import {
BoldIcon,
ItalicIcon,
UnderlineIcon,
StrikethroughIcon,
CodeIcon
} from 'lucide-react';
function CompleteToolbar() {
const editor = useYooptaEditor();
return (
<FloatingToolbar>
<FloatingToolbar.Content>
<FloatingToolbar.Group>
<FloatingToolbar.Button
onClick={() => Marks.toggle(editor, { type: 'bold' })}
active={Marks.isActive(editor, { type: 'bold' })}
title="Bold (⌘B)"
>
<BoldIcon size={16} />
</FloatingToolbar.Button>
<FloatingToolbar.Button
onClick={() => Marks.toggle(editor, { type: 'italic' })}
active={Marks.isActive(editor, { type: 'italic' })}
title="Italic (⌘I)"
>
<ItalicIcon size={16} />
</FloatingToolbar.Button>
<FloatingToolbar.Button
onClick={() => Marks.toggle(editor, { type: 'underline' })}
active={Marks.isActive(editor, { type: 'underline' })}
title="Underline (⌘U)"
>
<UnderlineIcon size={16} />
</FloatingToolbar.Button>
<FloatingToolbar.Button
onClick={() => Marks.toggle(editor, { type: 'strike' })}
active={Marks.isActive(editor, { type: 'strike' })}
title="Strikethrough"
>
<StrikethroughIcon size={16} />
</FloatingToolbar.Button>
</FloatingToolbar.Group>
<FloatingToolbar.Separator />
<FloatingToolbar.Group>
<FloatingToolbar.Button
onClick={() => Marks.toggle(editor, { type: 'code' })}
active={Marks.isActive(editor, { type: 'code' })}
title="Code"
>
<CodeIcon size={16} />
</FloatingToolbar.Button>
</FloatingToolbar.Group>
</FloatingToolbar.Content>
</FloatingToolbar>
);
}
With Highlight Color Picker
import { FloatingToolbar } from '@yoopta/ui';
import { HighlightColorPicker } from '@yoopta/ui';
import { Marks, useYooptaEditor } from '@yoopta/editor';
import { HighlighterIcon } from 'lucide-react';
function ToolbarWithHighlight() {
const editor = useYooptaEditor();
const highlightValue = Marks.getValue(editor, { type: 'highlight' }) as
| { color?: string; backgroundColor?: string }
| null;
return (
<FloatingToolbar>
<FloatingToolbar.Content>
<FloatingToolbar.Group>
<HighlightColorPicker
value={highlightValue ?? {}}
presets={['#FFFF00', '#FFE066', '#FFCC99', '#FF9999']}
onChange={(values) => {
Marks.add(editor, {
type: 'highlight',
value: {
color: values.color,
backgroundColor: values.backgroundColor,
},
});
}}
>
<FloatingToolbar.Button
active={Marks.isActive(editor, { type: 'highlight' })}
title="Highlight"
style={{
backgroundColor: highlightValue?.backgroundColor,
color: highlightValue?.color,
}}
>
<HighlighterIcon size={16} />
</FloatingToolbar.Button>
</HighlightColorPicker>
</FloatingToolbar.Group>
</FloatingToolbar.Content>
</FloatingToolbar>
);
}
Frozen State (with Popover)
import { FloatingToolbar } from '@yoopta/ui';
import { useState, useRef } from 'react';
import { ActionMenuList } from '@yoopta/ui';
import { ChevronDownIcon } from 'lucide-react';
function ToolbarWithMenu() {
const [menuOpen, setMenuOpen] = useState(false);
const triggerRef = useRef(null);
return (
<>
<FloatingToolbar frozen={menuOpen}>
<FloatingToolbar.Content>
<FloatingToolbar.Group>
<FloatingToolbar.Button
ref={triggerRef}
onClick={() => setMenuOpen(true)}
>
Turn into
<ChevronDownIcon size={16} />
</FloatingToolbar.Button>
</FloatingToolbar.Group>
</FloatingToolbar.Content>
</FloatingToolbar>
<ActionMenuList
open={menuOpen}
onOpenChange={setMenuOpen}
anchor={triggerRef.current}
/>
</>
);
}
Render Props Pattern
import { FloatingToolbar } from '@yoopta/ui';
function ConditionalToolbar() {
return (
<FloatingToolbar>
{({ isOpen }) => (
<FloatingToolbar.Content>
{isOpen && (
<FloatingToolbar.Group>
{/* Buttons */}
</FloatingToolbar.Group>
)}
</FloatingToolbar.Content>
)}
</FloatingToolbar>
);
}
Behavior
Selection Tracking
The toolbar automatically:
- Shows when text is selected
- Hides when selection is collapsed
- Positions above the selected text
- Handles multi-block selections
- Respects frozen state
Positioning
Uses Floating UI for smart positioning:
- Flips to bottom if no space above
- Shifts horizontally to stay in viewport
- Updates position on scroll/resize
- Accounts for inline elements
Click Behavior
Prevents text selection from collapsing on button clicks (especially important on Safari).
Styling
CSS Classes
.yoopta-ui-floating-toolbar {
/* Toolbar container */
}
.yoopta-ui-floating-toolbar-group {
/* Button group */
}
.yoopta-ui-floating-toolbar-button {
/* Individual button */
}
.yoopta-ui-floating-toolbar-button[data-active="true"] {
/* Active button state */
}
.yoopta-ui-floating-toolbar-separator {
/* Separator line */
}
Custom Styling
<FloatingToolbar className="my-toolbar">
<FloatingToolbar.Content className="my-toolbar-content">
<FloatingToolbar.Button className="my-button">
{/* ... */}
</FloatingToolbar.Button>
</FloatingToolbar.Content>
</FloatingToolbar>
TypeScript
import type {
FloatingToolbarRootProps,
FloatingToolbarContentProps,
FloatingToolbarGroupProps,
FloatingToolbarButtonProps,
FloatingToolbarSeparatorProps,
FloatingToolbarApi,
} from '@yoopta/ui';
See Also