Theme studio

Design a theme, preview it live, then export it. Saved in this browser.

Quick picks #10b981
Generated scale
50100200300400500600700800900
Some text is below AA

RTEBubbleMenu

  • Stable
  • WCAG 2.2 evidence
  • RTL

A floating formatting toolbar next to selected text. A non-modal React Aria Popover anchored to triggerRef (or to a rectangle from getTargetRect) holding a role="toolbar": the editor stays usable while it is shown, nothing is trapped (WCAG 2.1.2), the tools are one tab stop with arrows, Home and End (2.1.1), and Escape inside the menu closes it and returns focus to where it was before (the editor) (2.4.3). The menu flips to stay inside the viewport and wraps in narrow ones (1.4.10). It supplements the main toolbar and is never the only way to format. Consumer duties: open it on selection (isOpen), close it when the selection collapses, give it a name, and offer a keyboard way in (shouldFocusOnOpen with a shortcut such as Alt+F10).

import { RTEBubbleMenu } from "@nexera-ui/react";
Loading example…
3
examples
23
props
3
live controls
1
platform
7
WCAG criteria
1
block uses it

Try every prop. Copy the code.

Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.

Loading…
children
shouldFocusOnOpen
placement
Generated code
import { RTEBubbleMenu } from "@nexera-ui/react";

<RTEBubbleMenu />

Examples 2

The same examples as Storybook, rendered live. Open Code to copy one.

On selection

Realistic use with a plain contenteditable element: select text to show the menu above the selection (getTargetRect); press Alt+F10 in the editor to move focus into it; Escape returns to the editor.

Loading example…

In editor

A realistic composed editor with a plain contenteditable element (select text in the editor to show the bubble menu; Alt+F10 moves into it).

Loading example…

Props 23

Press "Try it" on a card to load that prop into the playground.

23 props shown

children*Nexera
ReactNode

The tools. They behave like an RTEToolbar: one tab stop, arrows, Home and End.

Default –
triggerRef*Nexera
RefObject<Element | null>

The element the menu is positioned against, usually the editor's content element. With getTargetRect the menu is placed against a rectangle inside it instead, for example the selection (() => window.getSelection()?.getRangeAt(0).getBoundingClientRect()). The library has no selection engine.

Default –
shouldFocusOnOpenNexera
boolean

Moves focus to the first tool when the menu opens. Use it when the menu is opened from the keyboard (for example Alt+F10); leave it off when it appears on text selection, so typing continues in the editor.

Default false
placementNexera
"bottom" | "bottom left" | "bottom right" | "bottom start" | "bottom end" | "top" | "top left" | "top right" | "top start" | "top end" | "left" | "left top" | "left bottom" | "start" | "start top" | "start bottom" | "right" | "right top" | "right bottom" | "end" | "end top" | "end bottom"

Side of the anchor the menu opens on; it flips to stay inside the viewport.

Default top
classNameNexera
string

Extra classes for the surface, merged last so they win over the defaults.

Default –
styleNexera
CSSProperties

Inline style for the surface.

Default –
aria-labelNexera
string

Accessible name of the toolbar ("Text formatting"). Translate it. Accessible name; aria-labelledby wins when both are set.

Default –
aria-labelledbyNexera
string

Id(s) of element(s) that name the toolbar; wins over aria-label. Id(s) of the visible element(s) that name the toolbar.

Default –
isOpenReact Aria
boolean

Whether the overlay is open by default (controlled).

Default –
containerPaddingReact Aria
number

The placement padding that should be applied between the element and its surrounding container.

Default 12
offsetReact Aria
number

The additional offset applied along the main axis between the element and its anchor element.

Default 8
crossOffsetReact Aria
number

The additional offset applied along the cross axis between the element and its anchor element.

Default 0
shouldFlipReact Aria
boolean

Whether the element should flip its orientation (e.g. top to bottom or left to right) when there is insufficient room for it to render completely.

Default true
boundaryElementReact Aria
Element

Element that that serves as the positioning boundary.

Default document.body
scrollRefReact Aria
RefObject<Element | null>

A ref for the scrollable region within the overlay.

Default overlayRef
shouldUpdatePositionReact Aria
boolean

Whether the overlay should update its position automatically.

Default true
maxHeightReact Aria
number

The maxHeight specified for the overlay element. By default, it will take all space up to the current viewport height.

Default –
arrowBoundaryOffsetReact Aria
number

The minimum distance the arrow's edge should be from the edge of the overlay element.

Default 0
getTargetRectReact Aria
(target: Element) => DOMRect | null

Overrides the target element's bounding rectangle. Useful for positioning relative to a specific point such as the mouse cursor (e.g. context menus) or text selection. @param target - The target element.

Default target.getBoundingClientRect()
isKeyboardDismissDisabledReact Aria
boolean

Whether pressing the escape key to close the popover should be disabled. Most popovers should not use this option. When set to true, an alternative way to close the popover with a keyboard must be provided.

Default false
shouldCloseOnInteractOutsideReact Aria
(element: Element) => boolean

When user interacts with the argument element outside of the popover ref, return true if onClose should be called. This gives you a chance to filter out interaction with elements that should not dismiss the popover. By default, onClose will always be called on interaction outside the popover ref.

Default –
defaultOpenReact Aria
boolean

Whether the overlay is open by default (uncontrolled).

Default –
onOpenChangeReact Aria
(isOpen: boolean) => void

Handler that is called when the overlay's open state changes.

Default –

* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.

Accessible by default.

Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.

WCAG 2.2 evidence

4 direct · 3 supporting
  • 1.3.1Info and RelationshipsLevel A · tested directly
  • 1.3.2Meaningful SequenceLevel A · supporting test
  • 1.4.10ReflowLevel AA · supporting test
  • 2.1.1KeyboardLevel A · tested directly
  • 2.3.3Animation from InteractionsLevel AAA · supporting test
  • 2.4.3Focus OrderLevel A · tested directly
  • 4.1.2Name, Role, ValueLevel A · tested directly

Fits any width.

Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.

0 px · drag the corner

Styling hooks

Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.

Usage
<RTEBubbleMenu className="shadow-sm" />

Used in blocks

Related components