Skip to content

Type to search the docs, API, and blog.

↑↓ navigate↵ openesc close
Zazz 0.7 alpha
API navigation

API

Callout

A bordered box for notes and status messages, set apart from the surrounding text.

Installation

pnpm dlx zazz-ui add callout
npx zazz-ui add callout
yarn dlx zazz-ui add callout
bunx zazz-ui add callout

Run zazz-ui init first if the project has no zazz/ folder yet.

Examples

Aside

A quieter surface for tips and context that readers can skip.

Scheduled maintenance

The dashboard is read-only on Saturday from 2 to 4 a.m. UTC.

Payment received

Your invoice is paid, and a receipt is on its way to your inbox.

Your trial ends in 3 days

Add a payment method to keep your projects running.

Deleting a workspace can't be undone

Its projects, files, and members are removed for good.

<div
  style="
    --display: grid;
    --gap: 4;
  "
>
  <aside data-ui="callout" aria-labelledby="callout-note">
    <p
      id="callout-note"
      data-ui="text-sm"
      style="
        --display: flex;
        --items: center;
        --gap: 2;
        --font-weight: strong;
      "
    >
      <svg
        style="
          --shrink: 0;
          --size: 4;
        "
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 20 20"
        fill="currentColor"
        aria-hidden="true"
      >
        <path
          fill-rule="evenodd"
          d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z"
          clip-rule="evenodd"
        />
      </svg>
      Note
    </p>
    <p data-ui="text-sm">Callouts set supporting information apart from the text around it.</p>
  </aside>
  <div data-ui="callout" data-callout-variant="muted">
    <p
      data-ui="text-sm"
      style="
        --display: flex;
        --items: center;
        --gap: 2;
        --font-weight: strong;
      "
    >
      <svg
        style="
          --shrink: 0;
          --size: 4;
        "
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 20 20"
        fill="currentColor"
        aria-hidden="true"
      >
        <path
          fill-rule="evenodd"
          d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z"
          clip-rule="evenodd"
        />
      </svg>
      Aside
    </p>
    <p data-ui="text-sm">A quieter surface for tips and context that readers can skip.</p>
  </div>
  <div data-ui="callout" data-callout-variant="info">
    <p
      data-ui="text-sm"
      style="
        --display: flex;
        --items: center;
        --gap: 2;
        --font-weight: strong;
      "
    >
      <svg
        style="
          --shrink: 0;
          --size: 4;
        "
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 20 20"
        fill="currentColor"
        aria-hidden="true"
      >
        <path
          fill-rule="evenodd"
          d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z"
          clip-rule="evenodd"
        />
      </svg>
      Scheduled maintenance
    </p>
    <p data-ui="text-sm">The dashboard is read-only on Saturday from 2 to 4 a.m. UTC.</p>
  </div>
  <div data-ui="callout" data-callout-variant="success">
    <p
      data-ui="text-sm"
      style="
        --display: flex;
        --items: center;
        --gap: 2;
        --font-weight: strong;
      "
    >
      <svg
        style="
          --shrink: 0;
          --size: 4;
        "
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 20 20"
        fill="currentColor"
        aria-hidden="true"
      >
        <path
          fill-rule="evenodd"
          d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
          clip-rule="evenodd"
        />
      </svg>
      Payment received
    </p>
    <p data-ui="text-sm">Your invoice is paid, and a receipt is on its way to your inbox.</p>
  </div>
  <div data-ui="callout" data-callout-variant="warning">
    <p
      data-ui="text-sm"
      style="
        --display: flex;
        --items: center;
        --gap: 2;
        --font-weight: strong;
      "
    >
      <svg
        style="
          --shrink: 0;
          --size: 4;
        "
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 24 24"
        fill="currentColor"
        aria-hidden="true"
      >
        <path
          fill-rule="evenodd"
          d="M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z"
          clip-rule="evenodd"
        />
      </svg>
      Your trial ends in 3 days
    </p>
    <p data-ui="text-sm">Add a payment method to keep your projects running.</p>
  </div>
  <div data-ui="callout" data-callout-variant="destructive">
    <p
      data-ui="text-sm"
      style="
        --display: flex;
        --items: center;
        --gap: 2;
        --font-weight: strong;
      "
    >
      <svg
        style="
          --shrink: 0;
          --size: 4;
        "
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 20 20"
        fill="currentColor"
        aria-hidden="true"
      >
        <path
          fill-rule="evenodd"
          d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z"
          clip-rule="evenodd"
        />
      </svg>
      Deleting a workspace can't be undone
    </p>
    <p data-ui="text-sm">Its projects, files, and members are removed for good.</p>
  </div>
</div>
/**
 * callout.css — Callout ([data-ui~="callout"])
 *
 * @layer      variables, components
 * @requires   _layers.css, _variables.css, _properties.css (--_*-resolved)
 * @uses       oklch(from …): status tints
 * @tokens     --ui-callout-* (@layer variables; named after the utilities they back)
 * @see        badge.css (status tint and border formulas; the test keeps them in sync)
 * @presets    data-callout-variant="muted" | "info" | "success" | "warning" | "destructive"
 *
 * A callout is an aside or alert: a padded grid with a gap, a border, and a
 * radius. The default matches an outline card and muted a muted card. Info,
 * success, and warning take the matching badge's tint and border, with the
 * role mixed toward --color-foreground for text; destructive is the badge's
 * solid fill.
 * Every variant keeps the 1px border (muted makes it transparent), so every
 * variant is the same size.
 * Its parts are plain elements laid out with utilities. Use <aside> for a
 * side note, or a <div> with role="status" or role="alert" for a message
 * that follows something the user did.
 * Every utility-backed declaration reads one chain, highest first:
 *   var(--_<utility>-resolved, var(--_callout-<utility>, var(--ui-callout-<utility>)))
 */

@layer variables {
  :root {
    --ui-callout-bg: var(--color-card);
    --ui-callout-text: var(--color-card-foreground);
    --ui-callout-rounded: var(--radius-md);
    --ui-callout-shadow: none;

    --ui-callout-border-width: 1px;
    --ui-callout-border-style: solid;
    --ui-callout-border-color: var(--color-border);

    /* dual-mode: a scale number or a length */
    --ui-callout-gap: var(--space-xs);
    --ui-callout-p: var(--space-sm);
  }
}

/* Variant privates: non-inheriting so a variant never cascades into a nested callout. */
@property --_callout-bg {
  syntax: "*";
  inherits: false;
}

@property --_callout-text {
  syntax: "*";
  inherits: false;
}

@property --_callout-border-color {
  syntax: "*";
  inherits: false;
}

@layer ui.components {
  :where([data-ui~="callout"]) {
    display: grid;
    --_gap-len: var(--_gap-resolved, var(--ui-callout-gap));
    --_gap-num: var(--_gap-resolved, var(--ui-callout-gap));
    gap: calc(var(--_gap-len) + var(--_gap-num) * var(--spacing));
    --_p-len: var(--_p-resolved, var(--ui-callout-p));
    --_p-num: var(--_p-resolved, var(--ui-callout-p));
    padding: calc(var(--_p-len) + var(--_p-num) * var(--spacing));
    color: var(--_text-resolved, var(--_callout-text, var(--ui-callout-text)));
    background-color: var(--_bg-resolved, var(--_callout-bg, var(--ui-callout-bg)));
    border-width: var(--_border-width-resolved, var(--ui-callout-border-width));
    border-style: var(--_border-style-resolved, var(--ui-callout-border-style));
    border-color: var(
      --_border-color-resolved,
      var(--_callout-border-color, var(--ui-callout-border-color))
    );
    border-radius: var(--_rounded-resolved, var(--ui-callout-rounded));
    box-shadow: var(--_shadow-resolved, var(--ui-callout-shadow));
  }

  /* ===========================================================================
  CALLOUT VARIANTS — data-callout-variant writes the privates
  =========================================================================== */

  :where([data-ui~="callout"][data-callout-variant="muted"]) {
    --_callout-bg: var(--color-muted);
    --_callout-text: var(--color-foreground);
    --_callout-border-color: transparent;
  }

  /* status variants: the soft status colors buttons and badges use (see
     button.css), plus a faint status border that outlines the block */

  :where([data-ui~="callout"][data-callout-variant="info"]) {
    --_callout-bg: light-dark(
      oklch(from var(--color-info) l c h / 0.1),
      oklch(from var(--color-info) l c h / 0.2)
    );
    --_callout-text: light-dark(
      oklch(from var(--color-info) min(l, 0.45) c h),
      oklch(from var(--color-info) max(l, 0.82) c h)
    );
    --_callout-border-color: oklch(from var(--color-info) l c h / 0.2);
  }

  :where([data-ui~="callout"][data-callout-variant="success"]) {
    --_callout-bg: light-dark(
      oklch(from var(--color-success) l c h / 0.1),
      oklch(from var(--color-success) l c h / 0.2)
    );
    --_callout-text: light-dark(
      oklch(from var(--color-success) min(l, 0.45) c h),
      oklch(from var(--color-success) max(l, 0.82) c h)
    );
    --_callout-border-color: oklch(from var(--color-success) l c h / 0.2);
  }

  :where([data-ui~="callout"][data-callout-variant="warning"]) {
    --_callout-bg: light-dark(
      oklch(from var(--color-warning) l c h / 0.1),
      oklch(from var(--color-warning) l c h / 0.2)
    );
    --_callout-text: light-dark(
      oklch(from var(--color-warning) min(l, 0.45) c h),
      oklch(from var(--color-warning) max(l, 0.82) c h)
    );
    --_callout-border-color: oklch(from var(--color-warning) l c h / 0.2);
  }

  :where([data-ui~="callout"][data-callout-variant="destructive"]) {
    --_callout-bg: light-dark(
      oklch(from var(--color-destructive) l c h / 0.1),
      oklch(from var(--color-destructive) l c h / 0.2)
    );
    --_callout-text: light-dark(
      oklch(from var(--color-destructive) min(l, 0.45) c h),
      oklch(from var(--color-destructive) max(l, 0.82) c h)
    );
    --_callout-border-color: oklch(from var(--color-destructive) l c h / 0.2);
  }
}

Attributes

callout attributes
AttributeKindValuesNotes
data-ui="callout"Identityfree valueIdentity token in data-ui.
data-callout-variantPresetdestructive info muted success warningPreset: a named bundle of values.

Hooks

Set a hook on :root, on a subtree, or inline on one element. A state hook (--…--hover) themes that state only; the primitive keeps its other states.

callout hooks
HookDefaultState
--ui-callout-bgvar(--color-card)—
--ui-callout-border-colorvar(--color-border)—
--ui-callout-border-stylesolid—
--ui-callout-border-width1px—
--ui-callout-gapvar(--space-xs)—
--ui-callout-pvar(--space-sm)—
--ui-callout-roundedvar(--radius-md)—
--ui-callout-shadownone—
--ui-callout-textvar(--color-card-foreground)—