blokhaus

CalloutNode

Styled callout/alert block with emoji and color presets.

CalloutNode is an ElementNode (not a DecoratorNode) that renders a styled callout block with an emoji indicator and a color preset. Because it extends ElementNode, it can contain standard Lexical children (paragraphs, text, lists, etc.) just like a blockquote.

Import

import {
  CalloutNode,
  $createCalloutNode,
  $isCalloutNode,
} from "@blokhaus/core";
import type { CalloutPayload } from "@blokhaus/core";

CalloutPayload

interface CalloutPayload {
  emoji?: string;
  colorPreset?: string;
  key?: NodeKey;
}
FieldTypeRequiredDefaultDescription
emojistringNo"💡"The emoji displayed as the callout indicator.
colorPresetstringNo"default"The color preset ID. Must match a CalloutPreset.id.
keyNodeKeyNoautoExplicit Lexical node key.

Functions

$createCalloutNode(payload?: CalloutPayload): CalloutNode

Creates a new CalloutNode. All fields are optional with sensible defaults. Must be called inside editor.update().

editor.update(() => {
  const callout = $createCalloutNode({
    emoji: "\u{26A0}\u{FE0F}", // warning sign
    colorPreset: "warning",
  });
  const paragraph = $createParagraphNode();
  paragraph.append($createTextNode("This is a warning callout."));
  callout.append(paragraph);
  $getRoot().append(callout);
});

$isCalloutNode(node: LexicalNode | null | undefined): node is CalloutNode

Type guard that returns true if the given node is a CalloutNode.

Instance methods

MethodReturnsDescription
getEmoji()stringReturns the current emoji. Uses getLatest() for read safety.
setEmoji(emoji: string)thisSets the emoji. Uses getWritable() internally. Must be called inside editor.update().
getColorPreset()stringReturns the current color preset ID. Uses getLatest() for read safety.
setColorPreset(preset: string)thisSets the color preset. Uses getWritable() internally. Must be called inside editor.update().

ElementNode characteristics

Unlike DecoratorNode-based nodes (ImageNode, CodeBlockNode), CalloutNode extends ElementNode. This means:

  • It contains children in the Lexical AST. You can append paragraphs, lists, and other block-level nodes inside it.
  • It participates in Lexical's native text selection. Users can select text across callout boundaries.
  • It uses Lexical's theme system for CSS class assignment.

getDOMSlot

The CalloutNode uses Lexical's getDOMSlot() API to handle its DOM structure correctly. The createDOM() method renders a non-editable emoji <span> inside the container <div>. The getDOMSlot() method tells Lexical's reconciler to insert children after this emoji span, preventing Lexical from overwriting the decorative element.

getDOMSlot(element: HTMLElement): ElementDOMSlot {
  const emojiSpan = element.querySelector('[data-callout-emoji-display]');
  return super.getDOMSlot(element).withAfter(emojiSpan);
}

Serialized format

type SerializedCalloutNode = SerializedElementNode & {
  type: "callout";
  version: 1;
  emoji: string;
  colorPreset: string;
};

Because CalloutNode extends ElementNode, the serialized form includes a children array (inherited from SerializedElementNode).

DOM behavior

  • exportDOM: Produces a <div> with data-callout-emoji and data-callout-color attributes.
  • importDOM: Converts pasted <div> elements that have a data-callout-emoji attribute back into CalloutNode instances.

CSS theming

The callout uses theme-based CSS classes:

  • The base class comes from config.theme.callout.
  • If the color preset is not "default", an additional class blokhaus-callout--{preset} is added.

Color presets map to CSS variables defined in tokens.css:

/* Example: warning preset */
.blokhaus-callout--warning {
  background: var(--blokhaus-callout-warning-bg);
  border-left-color: var(--blokhaus-callout-warning-border);
}

Default presets

Blokhaus ships with six built-in callout presets:

IDLabelDefault EmojiBackgroundBorder
defaultDefault💡#f1f1ef#d4d4d4
infoInfoâ„šī¸#ddebf1#0b6e99
warningWarningâš ī¸#fbf3db#dfab01
errorErrorđŸšĢ#fbe4e4#e03e3e
successSuccess✅#ddedea#0f7b6c
purpleNote📝#eae4f2#6940a5

See Data & Presets for the full CalloutPreset interface.