Variables

A value filled in per recipient, typed as {{ and kept as a node.

A variable is a value the sender fills in per recipient: a first name, an email address. In the editor it is an inline element shown as a chip, so it can be neither mistyped nor half deleted, and a renderer substitutes it without parsing text. Typing {{ opens the suggestions.

Hello First name,
Your spot for Saturday is confirmed. Type {{ for a variable.
See you there, The team

Setting it up

createCorrespondenceFeatures() and createEmailFeatures() include it. In another list of features, add variableFeature. Either way, pass the root the variables it offers. A variable is a name, which the node stores and the renderer substitutes, and an optional label, which the chip and the suggestions show.

import { ContentEditorField, createContentFeatures, variableFeature } from "@voila.dev/ui/content-editor";
 
<ContentEditorField
	features={[...createContentFeatures(), variableFeature]}
	variables={[
		{ name: "firstName", label: "Prénom" },
		{ name: "lastName", label: "Nom" },
		{ name: "email", label: "E-mail" },
	]}
	value={value}
	onChange={setValue}
/>

Typing

  • {{ opens the suggestions at the caret. Typing filters them on the name and the label; the arrow keys move, Enter or Tab picks.
  • Picking puts the chip at the caret, and the caret after it.
  • Escape gives back what was typed ({{fir), so a literal {{ stays possible. Backspace right after {{ leaves a single {.
  • A chip is a void element: the arrow keys step over it and Backspace deletes it whole.

The stored node

{ "type": "variable", "name": "firstName", "children": [{ "text": "" }] }

The reader writes the placeholder back as text, {{firstName}}, in HTML and in Markdown, for the renderer that substitutes it. variablePlaceholder(name) builds that string, and variableReader is the reader alone, for a server that renders stored content without the editor:

import { createContentReaders, variableReader } from "@voila.dev/ui/content-editor/reader";
 
const readers = [...createContentReaders(), variableReader];

A subject line is not a document: it keeps plain {{firstName}} text.

Labels

The suggestions' input and empty state are chrome.variablePlaceholder, chrome.insertVariable (its accessible name) and chrome.variablesEmpty.