Components · Data Display
Empty
The placeholder for a surface that has no data yet.
Examples
Image
Description
Empty · default illustration · a caption · an action
<!-- Paste-and-run: save as .html and open in a browser. No build step.
<aha-empty> is the SAME shared custom element React and Vue consume — here in its
native form. Theming comes only from the --aha-* tokens in tokens.css. -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/tokens.css">
<script type="module">
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/icons.js'; // registers <aha-icon> (custom-image slot)
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-empty.js'; // registers <aha-empty>
import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-button.js'; // registers <aha-button>
</script>
<!-- description="…" is the caption (or use the default slot); description="" hides it.
image="default" (line art) | "simple" (smaller, for tight surfaces).
slot="image" swaps in a custom picture; slot="action" is an optional CTA. -->
<aha-empty description="No responses yet — share the join link" style="width:280px">
<aha-button slot="action" variant="primary">Copy link</aha-button>
</aha-empty>
<!-- simple variant, custom illustration, no action -->
<aha-empty image="simple" description="No results">
<aha-icon slot="image" name="system-folder" size="40"></aha-icon>
</aha-empty>
import '@ahaslides-product/design/icons'; // registers <aha-icon> (custom-image slot)
import '@ahaslides-product/design/aha-empty'; // registers <aha-empty>
import '@ahaslides-product/design/aha-button'; // registers <aha-button>
// `description` is the caption (or use children); description="" hides it.
// image="default" | "simple"; slot="image" swaps in a custom picture; slot="action" is a CTA.
function NoResponses({ onShare }) {
return (
<aha-empty description="No responses yet — share the join link">
<aha-button slot="action" variant="primary" onClick={onShare}>Copy link</aha-button>
</aha-empty>
);
}
// simple variant with a custom illustration and no action
function NoResults() {
return (
<aha-empty image="simple" description="No results">
<aha-icon slot="image" name="system-folder" size="40" />
</aha-empty>
);
}
// usage
<NoResponses onShare={copyJoinLink} />
// main.ts — register the elements + mark aha-* as custom elements
import '@ahaslides-product/design/icons'; // registers <aha-icon> (custom-image slot)
import '@ahaslides-product/design/aha-empty';
import '@ahaslides-product/design/aha-button';
app.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('aha-');
// Component.vue
// `description` is the caption (or use the default slot); description="" hides it.
// image="default" | "simple"; slot="image" swaps in a custom picture; slot="action" is a CTA.
<template>
<aha-empty description="No responses yet — share the join link">
<aha-button slot="action" variant="primary" @click="copyJoinLink">Copy link</aha-button>
</aha-empty>
<!-- simple variant with a custom illustration and no action -->
<aha-empty image="simple" description="No results">
<aha-icon slot="image" name="system-folder" size="40" />
</aha-empty>
</template>
API
| Prop | Type | Default | Notes |
|---|---|---|---|
image | 'default' | 'simple' | default | Built-in illustration: 64×41 line art, or a smaller 48×30 low-key graphic for tight surfaces |
description | string | — | The caption; falls back to the default slot when absent, and renders nothing when set to "" |
(default slot) | slot | No data | The caption (alternative to the `description` attribute) |
image | slot | — | A custom picture (e.g. an <aha-icon>) that supersedes the built-in illustration |
action | slot | — | An optional call to action (a button or link) |
Install
# .npmrc — once: point the @ahaslides-product scope at GitHub Packages
@ahaslides-product:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} # a GitHub token with read:packages
npm i @ahaslides-product/design
import '@ahaslides-product/design/tokens.css'; // once, at the app root
import '@ahaslides-product/design/aha-empty'; // registers <aha-empty>
Agent feed for this component (absolute, fetchable anywhere): empty.agent.json · empty.md · empty.llms.txt
When to use
When to use
- Empty — a list, table, or panel has nothing to show yet
- Result — reporting the outcome of an action (success, 404)
- Skeleton — content is loading, not absent
The caption says what's missing and, ideally, the next step — 'No responses yet — share the join link'. Keep one action; an empty state is a nudge, not a menu.
Surfaces
editor dashboard settings audience
Spec
Layout centred column · gap 10 · padding 32/16 (simple: gap 8 · 20/16) · Illustration default 64×41 · simple 48×30 line art · #B5B5B5 (text-disabled) · Caption 14/22 (simple 13/20) #8A8A8A (text-tertiary) · hidden when description="" · Custom image slot="image" · supersedes the built-in art · Action slot="action" · hidden when empty