Skip to content
Edytor
Esc
↑↓navigate↵open⌘Jpreview
On this page

Placeholder

Show placeholder text in empty blocks with a string, a function of the block or the bundled Notion placeholders, and style it through the data-placeholder attribute.

A placeholder is hint text shown in an empty block, such as “Type ‘/’ for commands”. It is never part of the document: the editor renders it with CSS from a data-placeholder attribute.

Setting a placeholder

Pass placeholder to <Edytor>:

<script lang="ts">
	import { Edytor } from 'edytor';
</script>

<Edytor placeholder="Start writing…" />

A string shows in every empty block. A function decides per block:

<Edytor
	placeholder={({ type, data, focused }) => {
		if (type === 'heading') return `Heading ${String(data.level ?? 'h1').slice(1)}`;
		if (type === 'todo-item') return 'To-do';
		return focused ? "Type '/' for commands" : null;
	}}
/>

The function receives a view of the empty block and returns the text, or null for none:

PropType
type?string

The block's kind.

Typestring
data?object

The block's data.

Typeobject
focused?boolean

The caret is in the block.

Typeboolean
empty?boolean

Always true: the function is only asked for empty blocks.

Typeboolean

The function re-runs when the block’s kind, data or focus changes, so a placeholder can follow the caret. The prop itself is read once, when the editor mounts.

A plugin can supply the placeholder instead, with the same string or function:

import type { Plugin } from 'edytor';

export const hintsPlugin: Plugin = () => ({
	placeholder: ({ focused }) => (focused ? 'Press / for blocks, @ to mention' : null)
});

The <Edytor> prop wins over plugins; among plugins, the first one that declares a placeholder wins.

Notion placeholders

richTextPlaceholder is a ready-made function with Notion’s hints for the rich text and image kinds:

<script lang="ts">
	import { Edytor, richTextPlaceholder } from 'edytor';
</script>

<Edytor placeholder={richTextPlaceholder} />
Kind Placeholder
heading “Heading 1”, “Heading 2” or “Heading 3”
bulleted-list-item, numbered-list-item “List”
todo-item “To-do”
toggle “Toggle”
quote “Empty quote”
callout “Type something…”, only while focused
image (the caption) “Write a caption…”, only while focused
any other kind, such as paragraph “Type ‘/’ for commands”, only while focused

To change one case, wrap it: placeholder={(view) => (view.type === 'quote' ? 'Quote' : richTextPlaceholder(view))}.

When it shows

A block shows its placeholder when its content is a single empty text: no characters and no inline atoms. Its children do not count. It is withheld while an IME composition is in progress in the block, so the hint never overlaps composed text. Kinds that render no content (list containers, dividers) never show one.

Styling

The placeholder is an attribute on the empty text element:

<span data-edytor-text="true" data-placeholder="Start writing…">​</span>

The editor ships one rule that draws it:

[data-edytor-text][data-placeholder]::before {
	content: attr(data-placeholder);
	position: absolute;
	white-space: nowrap;
	pointer-events: none;
	user-select: none;
	opacity: 0.45;
}

It is positioned out of flow, so the caret stays at the start of the line and clicks go to the text. Override the look with your own rule:

[data-edytor] [data-placeholder]::before {
	color: #b6b4af;
	opacity: 1;
	font-style: italic;
}

To style by kind, go through the block element: [data-edytor-type='heading'] [data-placeholder]::before.

Was this page helpful?