Skip to content
Block Code & Assets

Rich Text

The <RichText /> component makes a control's value editable straight on the canvas, the way a caption on a core block is. The same value stays editable from the inspector, so the two are two views of one attribute. A name that matches no control works as well, and then the component registers and owns the attribute by itself.

Basic usage

Add the component to your block code and point it at a control by name:

<div useBlockProps>
  <RichText name="title" tagName="h2" placeholder="Add title…" />
</div>

The control named title now takes its text from the canvas. On the front end the component renders as the tag you gave it:

<div class="wp-block-lazyblock-your-block-name">
  <h2>Your typed title</h2>
</div>

Attributes

NameTypeDescription
nameStringcontrol or standalone attribute to bind to. Letters, numbers, - and _ only
tagNameStringtag to render, p by default. none renders the text with no tag around it
placeholderStringtext shown while the value is empty
allowedFormatsStringformats to offer, comma-separated or a JSON array. Everything, by default
inlineToolbarBooleanshow the formatting toolbar inline, true by default
withoutInteractiveFormattingBooleandrop formats that produce clickable elements, false by default
disableLineBreaksBooleanstop Enter from inserting a line break, false by default
defaultStringvalue a freshly inserted block starts with
translateStringtranslate="false" keeps the value out of WPML
formatStringaccepted and ignored
identifierStringaccepted and ignored
multilineStringaccepted and ignored

default seeds the block attribute the component registers, so a new block arrives with text in place instead of the placeholder. When the same name appears on more than one tag, the first tag that carries a default wins. The value is never printed on the rendered tag.

translate="false" on any tag takes that name out of the WPML config for the whole block. A name that belongs to a control follows the control's own WPML Translation setting instead. See Multilingual.

format, identifier and multiline are accepted and then stripped from the rendered tag. Nothing reads them. A single-line field is disableLineBreaks, not multiline.

Any other attribute is passed through to the rendered element, so class, id and data-* work as they do on a plain tag.

<div useBlockProps>
  <RichText
    name="intro"
    tagName="p"
    class="my-intro"
    allowedFormats="core/bold,core/italic"
    placeholder="Add an intro…"
  />
</div>

Give the component tagName="a" and it edits the link text on the canvas while rendering a real anchor on the front end, the same way the core Button block behaves. The link is not followable while you are editing it.

<div useBlockProps>
  <RichText
    name="label"
    tagName="a"
    href="https://example.com"
    placeholder="Add label…"
  />
</div>

href, target, rel and download are all passed through to the anchor.

Which controls it can bind to

The component works with the controls that store text:

ControlFormatting keptLine breaks
Rich Text (WYSIWYG)yesyes
Classic Editor (WYSIWYG)yesyes
Textareanoyes
Code Editornoyes
Textnono
URLnono
Emailnono

The component never stores more than the control behind it can hold. The same value is still edited by the control in the inspector, so putting HTML or a second line into a plain Text control would destroy it there. For those controls the component turns formatting and line breaks off by itself, whatever you passed in allowedFormats or disableLineBreaks.

Controls that store JSON rather than text, Image, Gallery and Repeater, cannot be bound, and neither can a control living inside a Repeater. Naming one warns in the browser console and leaves the value alone.

An empty value is offered for editing only while the block is selected, the same as a caption on a core block, and prints nothing on the front end.

A name with no control

name does not have to match a control. When no control carries that name, the component registers the block attribute itself, type: string with the tag's default or an empty string, and owns the value outright. Such a value is edited on the canvas only, because there is no inspector control mirroring it.

Two kinds of name are skipped even so, one the block already uses as an attribute of its own, and one belonging to a control with Save in Meta turned on, whose value lives in post meta rather than in the block attributes.

Escaping follows the same split. With no control behind the name the component owns the markup and keeps it through wp_kses_post(). A name bound to a control that is neither Rich Text nor Classic Editor is printed with esc_html(), so a tag typed into a plain Text control shows as text on the front end.

Notes

  • The control keeps appearing wherever its Placement setting puts it. Content places it in the canvas beside the component, Inspector puts it in the sidebar.
  • The component warns in the browser console when name is missing, names an attribute the block already has, names a Repeater child, or names a control that does not hold text.

Was this article helpful?

Copyright © 2026 Lazy Blocks.