Anatomy
- 1 Illustration — a decorative icon, SVG or custom asset in the illustration slot.
- 2 Content — a heading and a supporting description.
- 3 Actions — an optional primary next step.
Options
Presets
Each preset supplies a default heading, description and illustration icon. Any of these can be overridden while keeping the preset's overall intent.
Sizes
Container scaling
Use the Scale switch beside Light/Dark in the preview above, or set data-scale="small|medium|large" on a containing element. The illustration size, heading and description typography and the spacing inherit that context. A local size="sm" remains smaller within the chosen context; it does not cancel the container scale.
The default context is medium. A nested container replaces the inherited context explicitly, without multiplying the parent context again. Brand and light/dark mode remain independent.
Table of options
| Custom Element | Nunjucks | Values and defaults |
|---|---|---|
preset | preset | empty (default), error, no-results. Unsupported values fall back to empty. |
heading | heading | Heading text. Defaults to the preset heading. |
description | description | Description text. Defaults to the preset description. |
illustration-icon | illustrationIcon | Icon name. Defaults to the preset icon. |
action-label | actionLabel | Renders a single action when present. Empty by default. |
action-href | actionHref | Renders the action as a link; otherwise a button. Allowed URL prefixes: http:, https:, mailto:, tel:, / and #. Unsupported URLs fall back to #. |
action-variant | actionVariant | solid (default), outline, ghost. |
size | size | md (default) or sm. Relative to the inherited container scale. |
Behaviors
Optional action
An action appears only when a label is provided. With an href it renders as a link; otherwise as a button. Omit the action when there is no immediate recovery step.
Custom illustration slot
The Custom Element accepts a slot="illustration" and a slot="action" in light DOM, replacing the default icon and generated action when a plain icon is not enough.
Provide custom markup in the illustration region when an icon is not sufficient:
<uif-illustrated-message heading="Invite your team" description="Add collaborators to start working together.">
<span slot="illustration" class="uif-avatar xl" role="img" aria-label="Team"><span class="uif-avatar-initials">UI</span></span>
<a slot="action" class="uif-button solid" href="/invite">Invite teammates</a>
</uif-illustrated-message>
Usage guidelines
Do
Offer one clear next step that helps the user recover, such as clearing filters.
Don't
Do not expose raw error codes or internal jargon. Explain what happened in plain language.
Content standards
- Keep the heading short and concrete; describe the situation, not the system.
- Make the description actionable and reassuring.
- Use a single action label that names the next step as a verb phrase.
- Provide localized text. The component does not translate content.
Keyboard interactions
The message itself is not interactive. When an action is present it is a standard link or button:
| Key | Action |
|---|---|
| Tab | Moves focus to the action, when present. |
| Enter | Activates a link or button action. |
| Space | Activates a button action. |
Accessibility
- The illustration is decorative by default and carries
aria-hidden="true". Custom illustration markup remains exposed to assistive technology: provide an accessible name when it communicates unique meaning, or setaria-hidden="true"on the custom illustration when decorative. - The heading uses an
h2; confirm it fits the surrounding document outline, or adjust the level in a custom slot. - Keep the action focusable and clearly labelled.
- Do not rely on the illustration alone to convey the state; the heading and description carry the meaning.
Implementation
Import the individual module once, or use the aggregate ui-foundations/elements entry.
import "ui-foundations/elements/ui-illustrated-message";
<uif-illustrated-message preset="no-results" action-label="Clear filters" action-variant="outline"></uif-illustrated-message>
For static HTML without Custom Element JavaScript, use the macro:
{% import "macros/ui.njk" as uif %}
{{ uif.illustratedMessage(preset="empty", actionLabel="Create item") }}
The macro and Custom Element emit the same markup: a .uif-illustrated-message container with .uif-illustrated-message-illustration, .uif-illustrated-message-content (.uif-illustrated-message-heading and .uif-illustrated-message-description) and an optional .uif-illustrated-message-actions wrapper. Heading, description and action text are escaped.
Theming
Use the brand and mode switches in the preview above. Visual values come from the pattern's --uif-illustrated-message-* slots, which alias existing Semantic roles for content, subtle foreground, typography and spacing. Set data-brand and data-mode on the root element. See Design Tokens.
Tokens
| Token |
|---|
--_uif-context-scale |
--_uif-local-scale |
--_uif-scale-small |
--uif-illustrated-message-compat-heading-font-weight |
--uif-illustrated-message-content-gap |
--uif-illustrated-message-description-font-family |
--uif-illustrated-message-description-font-size |
--uif-illustrated-message-description-line-height |
--uif-illustrated-message-description-text-color |
--uif-illustrated-message-gap |
--uif-illustrated-message-heading-font-family |
--uif-illustrated-message-heading-font-size |
--uif-illustrated-message-heading-font-weight |
--uif-illustrated-message-heading-line-height |
--uif-illustrated-message-heading-text-color |
--uif-illustrated-message-illustration-color |
--uif-illustrated-message-illustration-size |
Design checklist
Automated checks cover markup, token resolution and naming. They do not certify complete accessibility or live design parity.