Skip to content

feat(rich-text-field): add RichTextField component#409

Open
s3rgiosan wants to merge 2 commits into
developfrom
feature/rich-text-field
Open

feat(rich-text-field): add RichTextField component#409
s3rgiosan wants to merge 2 commits into
developfrom
feature/rich-text-field

Conversation

@s3rgiosan
Copy link
Copy Markdown
Member

Description of the Change

Adds a new RichTextField component: a drop-in wrapper around RichText for use outside a block's edit context (e.g. inside InspectorControls or a Modal).

RichText only works correctly inside a block's edit because the surrounding block-editor infrastructure provides a SlotFillProvider, a block-selection store, and a BlockControls slot for the format toolbar. When rendered outside that context, the format toolbar disappears, selection state is missing, and formatting fills get captured by the parent block's toolbar.

RichTextField solves this by providing:

  1. A local SlotFillProvider so the format toolbar resolves inside the field instead of leaking into the surrounding block's toolbar.
  2. inlineToolbar so the format toolbar renders as a popover near the caret.
  3. Manual isSelected state with click-outside deselect that ignores the inline toolbar and any popovers it spawns (e.g. the link URL input).

The component accepts all RichText props except isSelected (managed internally) and forwards everything else through.

Files added/changed:

  • components/rich-text-field/index.tsx — component implementation (TypeScript).
  • components/rich-text-field/readme.md — usage, props, and modal z-index note.
  • components/index.ts — export RichTextField.
  • README.md — list the new component.

Closes #

How to test the Change

  1. npm install && npm run build in this repo.
  2. In a consumer plugin/theme, import the component:
    import { RichTextField } from '@10up/block-components';
  3. Use inside a block's InspectorControls panel:
    <InspectorControls>
        <PanelBody title="Notes">
            <RichTextField
                value={attributes.note}
                onChange={(note) => setAttributes({ note })}
                placeholder="Type and select to see the toolbar…"
            />
        </PanelBody>
    </InspectorControls>
    • Type text, select it, confirm inline format toolbar appears near the caret.
    • Confirm formatting (bold, italic, link) applies inside the sidebar field, not on the parent block.
    • Click outside the field; confirm the toolbar dismisses.
    • Open the link format, type a URL in the popover; confirm clicking inside the popover does not deselect the field.
  4. Repeat the same checks with RichTextField rendered inside a Modal. If the inline toolbar appears behind the modal, apply the CSS override documented in components/rich-text-field/readme.md.
  5. Verify tagName, placeholder, allowedFormats, and className props all forward correctly.

Changelog Entry

Added - RichTextField component for using RichText outside a block's edit context (e.g. InspectorControls, Modal).

Credits

Props @s3rgiosan

Checklist:

@s3rgiosan s3rgiosan requested a review from fabiankaegy May 12, 2026 10:46
Comment thread components/rich-text-field/index.tsx Outdated
Comment on lines +36 to +61
useEffect(() => {
if (!isSelected) {
return undefined;
}

const doc = ref.current?.ownerDocument;
if (!doc) {
return undefined;
}

const handleMouseDown = (event: MouseEvent) => {
const target = event.target as HTMLElement | null;
if (ref.current?.contains(target)) {
return;
}
if (target?.closest?.('.block-editor-rich-text__inline-format-toolbar')) {
return;
}
if (target?.closest?.('.components-popover')) {
return;
}
setIsSelected(false);
};

doc.addEventListener('mousedown', handleMouseDown);
return () => doc.removeEventListener('mousedown', handleMouseDown);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this get replaced by the useRefEffect hook?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

@s3rgiosan s3rgiosan requested a review from fabiankaegy May 12, 2026 11:47
@s3rgiosan s3rgiosan assigned fabiankaegy and unassigned s3rgiosan May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants