Empty State
v0.0.10
mix mishka.ui.gen.headless empty_state
Overview of the Phoenix and LiveView Headless Empty State Component
The Mishka Chelekom Headless Empty State is a placeholder for Phoenix and LiveView views that have nothing to show yet: no search results, an empty inbox, a new project. It renders a plain div with no role and no styling. An optional indicator holds an icon or illustration, a body holds the title, the description and any extra content, and an optional actions row holds buttons or links.
title and description are plain-string shorthands. For richer text, put markup in the default slot, which renders after the description. align accepts left, center or right and is exposed as data-align on the root, so CSS can flip the layout. Every part has a class attribute: class, indicator_class, body_class, title_class, description_class and actions_class.
Base UI Empty State example - no results (Phoenix headless)
Base UI Empty State example - no results (Phoenix headless)
<.empty_state
id="baseui-empty-state-hero"
title="No results found"
description="We couldn't find anything matching your search. Try a different keyword."
class="flex w-full max-w-72 flex-col items-center gap-3 text-center"
indicator_class="flex size-12 items-center justify-center rounded-full bg-neutral-100 text-neutral-500 dark:bg-neutral-800 dark:text-neutral-400"
body_class="flex flex-col gap-1"
title_class="text-base font-semibold text-neutral-950 dark:text-white"
description_class="text-sm text-neutral-600 dark:text-neutral-400"
>
<:indicator>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="size-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"
/>
</svg>
</:indicator>
</.empty_state>Base UI Empty State example - with actions (Phoenix headless)
Base UI Empty State example - with actions (Phoenix headless)
<.empty_state
id="baseui-empty-state-actions"
align="left"
title="No projects yet"
description="Create your first project to get started. It only takes a minute."
class="flex w-full max-w-80 flex-col items-start gap-3 text-left"
indicator_class="flex size-12 items-center justify-center rounded-full bg-neutral-100 text-neutral-500 dark:bg-neutral-800 dark:text-neutral-400"
body_class="flex flex-col gap-1"
title_class="text-base font-semibold text-neutral-950 dark:text-white"
description_class="text-sm text-neutral-600 dark:text-neutral-400"
actions_class="mt-2 flex gap-2"
>
<:indicator>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="size-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M12 10.5v6m3-3H9m4.06-7.19-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z"
/>
</svg>
</:indicator>
<:actions>
<.button class="rounded-md bg-neutral-950 px-3 py-1.5 text-sm font-medium text-white hover:bg-neutral-800 dark:bg-white dark:text-neutral-950 dark:hover:bg-neutral-200">New project</.button>
<.button class="rounded-md px-3 py-1.5 text-sm font-medium text-neutral-700 hover:bg-neutral-100 dark:text-neutral-300 dark:hover:bg-neutral-800">Import</.button>
</:actions>
</.empty_state>Announcing a dynamic empty state
The root accepts any global attribute, so the live-region role goes straight on the component.
<.empty_state
:if={@results == []}
role="status"
title="No results found"
description="Try a different keyword."
class="..."
/>Parts & data attributes
The root carries chelekom-empty-state and data-align. Each part has a data-part value and a chelekom-empty-state__* class.
indicatorholds the:indicatorslot. It is decorative and markedaria-hidden.bodywraps the title, the description, the default slot and the actions. It is rendered only when at least one of them is present.titleanddescriptionrender from the matching attributes. The title is adiv, not a heading. If your page outline needs a heading, leavetitleout and put one in the default slot.actionsholds the:actionsslot after the body content.
Accessibility
An empty state has no formal WAI-ARIA pattern, so the root has no role by default. Keep the meaningful information in the title and description text, because the indicator is hidden from assistive technology.
Attributes
| Name | Type | Default | Values | Required | Description |
|---|---|---|---|---|---|
id
|
string
| — | — | No | Optional unique id for the root element |
align
|
string
|
center
|
leftcenterright
| No | Content alignment; exposed as data-align |
title
|
string
| — | — | No | Heading text (shorthand); omit to use the body slot instead |
description
|
string
| — | — | No | Supporting text (shorthand) |
class
|
any
| — | — | No | Extra classes for the root |
indicator_class
|
any
| — | — | No | Extra classes for the indicator part |
body_class
|
any
| — | — | No | Extra classes for the body part |
title_class
|
any
| — | — | No | Extra classes for the title part |
description_class
|
any
| — | — | No | Extra classes for the description part |
actions_class
|
any
| — | — | No | Extra classes for the actions part |
rest
|
global
| — | — | No | — |
Slots
| Name | Required | Description |
|---|---|---|
indicator
| No | Icon or illustration shown above/beside the text (decorative) |
actions
| No | Optional call-to-action buttons rendered after the body |
inner_block
| No | Extra body content, rendered after the description |
Options
Each option takes one or more of its values, separated by commas.
| Option | Values |
|---|---|
--type
|
empty_state
|
--module
| A module name of your own |
What it generates
mix mishka.ui.gen.headless empty_state