Callout

Display brief, crucial messages in a noticeable way.

The callout component attracts the user’s attention to provide extra information. Keystone provides this component as a partial (for template use) and as a shortcode (for Markdown content).

The component leverages the partial decorators(Opens in a new tab) construct introduced in Hugo v0.154.0.

Origin Story
While flatbreads have existed for millennia, the modern pizza was invented in Naples, Italy, specifically to honor Queen Margherita.
Ingredient Selection
For the authentic Neapolitan taste, we recommend strictly using San Marzano tomatoes grown in the volcanic soil of Mount Vesuvius.
Why is the dough so sticky?
You might think you made a mistake, but high hydration (70%+) is actually desirable! Do not add more flour!
Chef's Secret
Letting the dough cold-ferment for 72 hours in the fridge is what creates that signature complex flavor and the leopard-spotting on the crust.
Common Mistake
Never use a rolling pin. Using a rolling pin crushes the air pockets (alveoli) in the dough, resulting in a flat, dense cracker instead of an airy crust.
High Heat Required
Your domestic oven must be pre-heated to its maximum setting (usually 500°F/260°C) for at least one hour before baking.
HTML
 1<div class="w-full max-w-xl mx-auto">
 2  <!-- Default with custom icon -->
 3  {{- with partial "ui/callout" (dict
 4    "title" "Origin Story" 
 5    "icon"  "pizza"
 6  )}}
 7    <p>While flatbreads have existed for millennia, the modern pizza was invented in <strong>Naples</strong>, Italy, specifically to honor <strong>Queen Margherita</strong>.</p>
 8  {{- end }}
 9
10  <!-- Success -->
11  {{- with partial "ui/callout" (dict 
12    "type"  "success"
13    "title" "Ingredient Selection"
14  )}}
15    <p>For the authentic Neapolitan taste, we recommend strictly using <strong>San Marzano tomatoes</strong> grown in the volcanic soil of Mount Vesuvius.</p>
16  {{- end }}
17
18  <!-- Question -->
19  {{- with partial "ui/callout" (dict 
20    "type"  "question"
21    "title" "Why is the dough so sticky?"
22  )}}
23    <p>You might think you made a mistake, but high hydration (70%+) is actually desirable! <strong>Do not add more flour!</strong></p>
24  {{- end }}
25
26  <!-- Info -->
27  {{- with partial "ui/callout" (dict 
28    "type"  "info"
29    "title" "Chef's Secret"
30  )}}
31    <p>Letting the dough <strong>cold-ferment for 72 hours</strong> in the fridge is what creates that signature complex flavor and the leopard-spotting on the crust.</p>
32  {{- end }}
33
34  <!-- Error -->
35  {{- with partial "ui/callout" (dict 
36    "type"  "error"
37    "title" "Common Mistake"
38  )}}
39    <p><strong>Never use a rolling pin.</strong> Using a rolling pin crushes the air pockets (<span lang="it">alveoli</span>) in the dough, resulting in a flat, dense cracker instead of an airy crust.</p>
40  {{- end }}
41
42  <!-- Warning -->
43  {{- with partial "ui/callout" (dict 
44    "type"  "warning"
45    "title" "High Heat Required"
46  )}}
47    <p>Your domestic oven must be pre-heated to its maximum setting (usually <em>500&#8451;/260&#8457;</em>) for at least <strong>one hour</strong> before baking.</p>
48  {{- end }}
49</div>

Reference

The component is composed of the ui/callout partial decorator and a child shortcode that simply calls the partial.

icon
"icon" "pizza" — (string, optional)
The name of the icon to display. Use "false" to disable the icon entirely.
Note: Requires the Icon component to be installed.
title
"title" "Origin Story" — (string, optional)
The header text of the callout.
type
"type" "default" — (string, optional)
Defines the visual style.
Values: default (default), error, info, question, success, warning

Installation

The Callout component is disabled by default to save resources.
Uncomment the import in the following file:

/assets/css/main.css
1- /* @import './components/_callout.css'; */
2+ @import './components/_callout.css';
Prerequisites
  1. The Get Started: Manual Installation steps must be completed!
  2. The Icon component must be installed.
    • For the default icons download the Callout Icon Pack and extract it to assets/icons/.

Hugo Partial

Create the ui/callout partial.

Go/HTML template layouts/_partials/ui/callout.html
 1{{- $type := .type | default "default" -}}
 2{{- $title := .title -}}
 3{{- $iconParam := .icon -}}
 4
 5{{- $finalContent := "" -}}
 6{{- if .content -}}
 7  {{- /* Called as a shortcode */ -}}
 8  {{- $finalContent = .content | strings.TrimSpace | markdownify -}}
 9{{- else -}}
10  {{- /* Called as a Decorator (HTML content) */ -}}
11  {{- $finalContent = (inner .) | strings.TrimSpace | safeHTML -}}
12{{- end -}}
13
14{{- $hasContent := gt (len $finalContent) 0 -}}
15
16{{- $iconName := "" -}}
17{{- $isIconDisabled := eq $iconParam "false" -}}
18
19{{- /* Icon Logic */}}
20{{- if not $isIconDisabled -}}
21  {{- /*
22    Default Mapping.
23    These files MUST exist in `assets/icons/callout/` for the component to work out-of-the-box.
24  */}}
25  {{- $iconMap := dict
26    "error"       "callout/circle-x"
27    "warning"     "callout/circle-alert"
28    "success"     "callout/circle-check"
29    "question"    "callout/circle-question-mark"
30    "info"        "callout/info"
31    "default"     "callout/circle"
32  -}}
33
34  {{- $iconName = $iconParam | default (index $iconMap $type | default "default") -}}
35{{- end -}}
36
37{{- /* Generate ID only if Title exists to avoid creating unused IDs */}}
38{{- $id := "" -}}
39{{- if $title -}}
40  {{- $id = printf "ks-callout-title-%d" (now.UnixNano) -}}
41{{- end -}}
42
43
44<div
45  class="ks-callout variant-{{ $type }}"
46  role="note"
47  {{- with $title }}aria-labelledby="{{ $id }}"{{- end }}
48>
49  {{- /* Icon Column */}}
50  {{- if $iconName }}
51    {{- if templates.Exists "_partials/ui/icon.html" -}}
52      {{- partial "ui/icon" (dict "name" $iconName) -}}
53    {{- else }}
54      {{- /* Empty div to keep grid alignment if icon exist but icon partial is missing */}}
55      <div></div>
56      {{- warnf "Keystone UI [callout]: Icon partial not found. Skipping icon '%s'." $iconName -}}
57    {{- end }}
58  {{- else }}
59    {{- /* Empty div to keep grid alignment if icon is missing */}}
60    <div></div>
61  {{- end }}
62
63  {{- /* Content Column */}}
64  <div>
65    {{- with $title }}
66      <div id="{{ $id }}" class="ks-callout-title">
67        {{ . }}
68      </div>
69    {{- end }}
70    {{- if $hasContent }}
71      <div class="ks-callout-description">
72        {{- $finalContent -}}
73      </div>
74    {{- end }}
75  </div>
76</div>

Hugo Shortcode

Warning
The shortcode is dependent on the partial above. Ensure the partial is created first.

Create the shortcode.

Go/HTML template layouts/_shortcodes/ui/callout.html
1{{ partial "ui/callout" (dict
2  "title"   (.Get "title")
3  "type"    (.Get "type")
4  "icon"    (.Get "icon")
5  "content" .Inner
6)}}

CSS Styling

Create the CSS component:

Tailwind CSS assets/css/components/_callout.css
 1@layer components {
 2  .ks-callout {
 3    @apply relative;
 4    @apply grid grid-cols-[0_1fr] items-start gap-y-0.5;
 5    @apply my-3 w-full px-4 py-3;
 6    @apply text-sm;
 7    @apply border-border rounded-lg border;
 8    @apply has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current;
 9
10    .ks-callout-title {
11      @apply col-start-2;
12      @apply min-h-4;
13      @apply line-clamp-1 font-medium tracking-tight;
14    }
15
16    .ks-callout-description {
17      @apply col-start-2;
18      @apply mt-1.5;
19      @apply text-muted-foreground text-sm [&_p]:leading-relaxed;
20    }
21
22    /* Variants */
23    &.variant-default {
24      @apply text-card-foreground bg-card;
25    }
26    &.variant-error {
27      @apply text-destructive border-red-200 bg-red-50/20 dark:border-red-900/50 dark:bg-red-950/30;
28    }
29    &.variant-info {
30      @apply border-blue-200 bg-blue-50/20 text-blue-800 dark:border-blue-900/50 dark:bg-blue-950/30 dark:text-blue-100;
31    }
32    &.variant-question {
33      @apply border-cyan-200 bg-cyan-50/20 text-cyan-800 dark:border-cyan-900/50 dark:bg-cyan-950/30 dark:text-cyan-100 [&>svg]:text-current;
34    }
35    &.variant-success {
36      @apply border-emerald-200 bg-emerald-50/20 text-green-800 dark:border-emerald-900/50 dark:bg-emerald-950/30 dark:text-green-100 [&>svg]:text-current;
37    }
38    &.variant-warning {
39      @apply border-amber-200 bg-amber-50/20 text-amber-900 dark:border-amber-900/50 dark:bg-amber-950/30 dark:text-amber-100 [&>svg]:text-current;
40    }
41  }
42}

Import it in your main Tailwind file:

Tailwind CSS assets/main.css
1/* Components */
2/** (Import Keystone components CSS here) */
3@import './components/_callout.css';

Usage

Use the component to attract the user’s attention for crucial or important pieces of information.

Using the Partial (Templates)

When working inside layout files (e.g. layouts/home.html), use the with context pattern. This is required because the partial acts as a decorator:

HTML layouts/home.html
1<div class="w-full max-w-lg mx-auto">
2<!-- Warning callout without content -->
3  {{- with partial "ui/callout" (dict
4    "type" "warning"
5    "title" "The website will be offline for maintenance from 00:00-02:00CET"
6  )}}
7  {{- end }}
8</div>

Using the Shortcode (Markdown)

Markdown content/_index.md
1<!-- Info callout, with custom icon, without content-->
2{{< ui/callout type="info" icon="pizza" title="Lunch break. Brb!">}}
3{{< /ui/callout >}}
Limitation

As shown in the examples, even when body content is not provided, you MUST close the tags:

  1. Partials: Use {{ with ... }} {{ end }}.
  2. Shortcodes: Use the closing tag

Tips & tricks

Semantic Roles

All types of callouts are designed to be static and use role="note". They should be considered part of the document flow.

Ensure the content text conveys the importance of the information, rather than relying solely on color.

Accessibility

The component is engineered to meet WCAG 2.2 guidelines:

  1. Contrast: The default color variants are designed to meet as minimum WCAG AA (4.5:1)(Opens in a new tab) contrast ratios.
  2. Screen Readers: Uses role="note" to provide a semantic hint to assistive technology that this content is parenthetic or ancillary to the main content.