blokhaus

CalloutPlugin

Styled callout blocks with emoji and color presets.

Import

import { CalloutPlugin } from "@blokhaus/core";

Overview

The CalloutPlugin provides styled callout blocks (also known as admonitions or notices) with customizable emoji icons and color presets. Callouts are visually distinct blocks used to highlight important information, warnings, tips, or notes. Each callout has a leading emoji, a configurable background color, and supports rich text content inside.

Props

PropTypeDefaultDescription
presetsCalloutPreset[]Built-in presetsCustom color presets. When provided, replaces the built-in set.
defaultEmojistring"💡"Default emoji for new callouts when no emoji is specified.
defaultPresetstring"default"The preset key to use for new callouts when no preset is specified.

The CalloutPreset interface

interface CalloutPreset {
  /** Unique identifier for this preset. */
  key: string;
  /** Display label shown in the preset selector. */
  label: string;
  /** CSS background color value or CSS variable reference. */
  backgroundColor: string;
  /** CSS border color value or CSS variable reference. */
  borderColor: string;
  /** CSS text color for the callout content. */
  textColor?: string;
}

Built-in presets

KeyLabelAppearance
"default"DefaultLight gray background, subtle border
"info"InfoLight blue background, blue border
"success"SuccessLight green background, green border
"warning"WarningLight yellow background, yellow border
"danger"DangerLight red background, red border

Usage

Basic setup

app/editor/page.tsx
"use client";

import {
  EditorRoot,
  CalloutPlugin,
  InputRulePlugin,
  SlashMenu,
} from "@blokhaus/core";

export default function EditorPage() {
  return (
    <EditorRoot namespace="my-editor">
      <InputRulePlugin />
      <SlashMenu />
      <CalloutPlugin />
    </EditorRoot>
  );
}

With custom presets

const customPresets = [
  {
    key: "tip",
    label: "Tip",
    backgroundColor: "hsl(142 76% 96%)",
    borderColor: "hsl(142 76% 46%)",
  },
  {
    key: "important",
    label: "Important",
    backgroundColor: "hsl(262 83% 96%)",
    borderColor: "hsl(262 83% 58%)",
  },
  {
    key: "caution",
    label: "Caution",
    backgroundColor: "hsl(38 92% 95%)",
    borderColor: "hsl(38 92% 50%)",
  },
];

<CalloutPlugin presets={customPresets} defaultEmoji="📝" defaultPreset="tip" />;

Registered commands

CommandPayloadDescription
INSERT_CALLOUT_COMMAND{ emoji?: string; colorPreset?: string }Inserts a callout block at the current cursor position.

Creating a callout programmatically

import { INSERT_CALLOUT_COMMAND } from "@blokhaus/core";

// Insert with defaults
editor.dispatchCommand(INSERT_CALLOUT_COMMAND, {});

// Insert with specific emoji and preset
editor.dispatchCommand(INSERT_CALLOUT_COMMAND, {
  emoji: "⚠️",
  colorPreset: "warning",
});

Floating toolbar

When the cursor is inside a callout, a floating toolbar appears above the block with two controls:

  1. Emoji picker -- Click the current emoji to open a small emoji selector. Changing the emoji updates the CalloutNode via a single editor.update() call.
  2. Color preset selector -- A row of colored circles representing the available presets. Clicking a preset changes the callout's background and border colors.

Callout structure in JSON

{
  "type": "callout",
  "emoji": "💡",
  "colorPreset": "info",
  "children": [
    {
      "type": "paragraph",
      "children": [
        { "type": "text", "text": "This is an informational callout." }
      ]
    }
  ]
}

Content inside callouts

Callout blocks support any block-level content: paragraphs, headings, lists, code blocks, and images. The callout acts as a container node in the AST.

editor.update(() => {
  const callout = $createCalloutNode("💡", "info");
  const heading = $createHeadingNode("h3");
  heading.append($createTextNode("Pro tip"));
  const paragraph = $createParagraphNode();
  paragraph.append($createTextNode("You can put any content inside callouts."));

  callout.append(heading, paragraph);
  $getRoot().append(callout);
});

Keyboard behavior

KeyContextAction
EnterEnd of last paragraph in calloutCreate a new paragraph inside the callout
Enter (x2)Empty paragraph at end of calloutExit the callout and create a paragraph below
BackspaceStart of first paragraph, callout is emptyDelete the callout block
Arrow DownLast line of calloutMove cursor to the next block after the callout
Arrow UpFirst line of calloutMove cursor to the block before the callout

Slash menu integration

When CalloutPlugin is mounted, a "Callout" item appears in the slash menu. Selecting it inserts a new callout with the defaultEmoji and defaultPreset, with the cursor positioned inside the callout body.

Type guards and helpers

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

// Check if a node is a callout
if ($isCalloutNode(node)) {
  console.log("Emoji:", node.getEmoji());
  console.log("Preset:", node.getColorPreset());
}

// Create a callout
const callout = $createCalloutNode("🔥", "danger");

Callout colors are applied via inline CSS custom properties on the callout container element. This allows the color presets to work without any additional CSS files, and ensures colors are consistent in both light and dark themes when using HSL values.

When providing custom presets, the built-in presets are completely replaced. If you want to extend the defaults, import DEFAULT_CALLOUT_PRESETS from @blokhaus/core and spread it into your custom array.