@mdxeditor/floating-selection-ui-plugin
v0.2.0
Published
MDXEditor plugin for displaying customizable floating UI when text is selected
Maintainers
Readme
@mdxeditor/floating-selection-ui-plugin
MDXEditor plugin for displaying customizable floating UI when text is selected. Shows a developer-provided React component positioned above text selections, similar to formatting toolbars in Dropbox Paper or Google Docs.
Installation
npm install @mdxeditor/floating-selection-ui-pluginpnpm add @mdxeditor/floating-selection-ui-pluginFeatures
- Floating UI appears above text selections
- Fully customizable React component
- Optional visibility control via
shouldShowhook
Usage
This plugin enables you to display any React component in a floating popover when users select text in the editor.
Basic Example
import { MDXEditor, listsPlugin, headingsPlugin } from "@mdxeditor/editor";
import { floatingSelectionUIPlugin } from "@mdxeditor/floating-selection-ui-plugin";
import type { FloatingUIComponentProps } from "@mdxeditor/floating-selection-ui-plugin";
import { $getSelection } from "lexical";
// Define your custom component
function FormatButton({ editor, close }: FloatingUIComponentProps) {
return (
<button
onClick={() => {
const selectedText = editor.getEditorState().read(() => {
const selection = $getSelection();
return selection?.getTextContent() || "";
});
console.log("Selected:", selectedText);
close();
}}
onMouseDown={(e) => {
// Prevent losing selection when clicking
e.preventDefault();
}}
>
Format
</button>
);
}
function App() {
return (
<MDXEditor
markdown="# Hello World\n\nSelect some text!"
plugins={[
listsPlugin(),
headingsPlugin(),
floatingSelectionUIPlugin({
component: FormatButton,
}),
]}
/>
);
}Advanced Example with Visibility Control
import { MDXEditor } from "@mdxeditor/editor";
import { floatingSelectionUIPlugin } from "@mdxeditor/floating-selection-ui-plugin";
import type { FloatingUIComponentProps } from "@mdxeditor/floating-selection-ui-plugin";
import { $getSelection } from "lexical";
function FormattingToolbar({ editor, close }: FloatingUIComponentProps) {
const handleBold = () => {
// Your formatting logic here
close();
};
return (
<div style={{ display: "flex", gap: "4px", padding: "4px" }}>
<button onClick={handleBold}>Bold</button>
<button onClick={() => close()}>Italic</button>
<button onClick={() => close()}>Link</button>
</div>
);
}
function App() {
return (
<MDXEditor
markdown="# Hello World"
plugins={[
floatingSelectionUIPlugin({
component: FormattingToolbar,
// Only show when more than 3 characters are selected
shouldShow: (editor) => {
const text = editor.getEditorState().read(() => {
const selection = $getSelection();
return selection?.getTextContent() || "";
});
return text.length > 3;
},
}),
]}
/>
);
}Custom Styled Component
import type { FloatingUIComponentProps } from "@mdxeditor/floating-selection-ui-plugin";
function StyledToolbar({ editor, close }: FloatingUIComponentProps) {
return (
<div
style={{
backgroundColor: "white",
padding: "8px",
borderRadius: "4px",
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
display: "flex",
gap: "8px",
}}
>
<button
style={{
padding: "4px 12px",
border: "none",
borderRadius: "4px",
cursor: "pointer",
backgroundColor: "#007acc",
color: "white",
}}
onMouseDown={(e) => e.preventDefault()}
onClick={() => {
// Your action here
close();
}}
>
Action
</button>
</div>
);
}API
Plugin Configuration
floatingSelectionUIPlugin({
component: ComponentType<FloatingUIComponentProps>,
shouldShow?: (editor: LexicalEditor) => boolean
})Parameters:
component(required): A React component that will be rendered in the floating UIshouldShow(optional): A function that determines whether the floating UI should be shown. Receives the Lexical editor instance and returns a boolean. If not provided, the UI will show whenever text is selected.
FloatingUIComponentProps Interface
Your component receives these props:
interface FloatingUIComponentProps {
editor: LexicalEditor; // The Lexical editor instance
close: () => void; // Function to close the floating UI
}Usage tips:
- Use
editor.getEditorState().read()to read selection and content - Call
close()to hide the floating UI programmatically - Add
onMouseDown={(e) => e.preventDefault()}to buttons to prevent losing selection
Important Notes
Preventing Selection Loss: When adding interactive elements (buttons, etc.), use
onMouseDown={(e) => e.preventDefault()}to prevent the selection from being cleared when the user clicks.Reading Selection: Always wrap selection reads in
editor.getEditorState().read():const text = editor.getEditorState().read(() => { const selection = $getSelection(); return selection?.getTextContent() || ""; });
Contributing
This package is part of the MDXEditor Extras monorepo. See the main repository for contribution guidelines.
License
MIT
