Components · Data Display
Descriptions
A read-only label/value grid summarising one entity's fields — N columns, bordered or plain, horizontal or vertical, with per-item span.
Examples
Bordered
Layout
Size
Columns
Descriptions · bordered · 2 columns · a spanning row · horizontal
<!-- Paste-and-run: save as .html and open in a browser. No build step.
<aha-descriptions> 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/aha-descriptions.js'; // registers <aha-descriptions>
</script>
<!-- items = [{label, value, span?}]; bordered | column="N" | size="default|small|large" | layout="horizontal|vertical" -->
<aha-descriptions desc-title="Account" bordered column="2" size="default" layout="horizontal" style="max-width:520px"
items='[
{"label":"Plan","value":"Pro"},
{"label":"Status","value":"Active"},
{"label":"Seats","value":"25 of 50"},
{"label":"Billing cycle","value":"Yearly"},
{"label":"Renews","value":"9 Sep 2027","span":2}
]'>
</aha-descriptions>
<!-- …or feed rows as light-DOM children (each child's label attr + content = one item): -->
<aha-descriptions desc-title="Plan" style="max-width:360px; margin-top:16px">
<div label="Tier">Pro</div>
<div label="Notes" span="2">Renews yearly · 25 of 50 seats used</div>
</aha-descriptions>
import '@ahaslides-product/design/aha-descriptions'; // registers <aha-descriptions>
// Feed an items tree ([{label, value, span?}]) — bordered, N columns, sized, laid out.
function AccountFacts({ title, items }) {
return (
<aha-descriptions
desc-title={title}
bordered
column="2"
size="default"
layout="horizontal"
items={JSON.stringify(items)}
/>
);
}
// usage
<AccountFacts
title="Account"
items={[
{ label: 'Plan', value: 'Pro' },
{ label: 'Status', value: 'Active' },
{ label: 'Seats', value: '25 of 50' },
{ label: 'Renews', value: '9 Sep 2027', span: 2 },
]}
/>
// main.ts — register the element + mark aha-* as custom elements
import '@ahaslides-product/design/aha-descriptions';
app.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('aha-');
// Component.vue
<script setup>
import { ref, computed } from 'vue';
const items = ref([
{ label: 'Plan', value: 'Pro' },
{ label: 'Status', value: 'Active' },
{ label: 'Seats', value: '25 of 50' },
{ label: 'Renews', value: '9 Sep 2027', span: 2 },
]);
const itemsJson = computed(() => JSON.stringify(items.value));
</script>
<template>
<!-- bordered | column="N" | size="default|small|large" | layout="horizontal|vertical" -->
<aha-descriptions desc-title="Account" bordered column="2" layout="horizontal" :items="itemsJson" />
</template>
API
| Prop | Type | Default | Notes |
|---|---|---|---|
items | JSON [{label,value,span?}] | — | The items, as a JSON tree. Alternative to light-DOM children |
desc-title | string | — | Renders an optional header row |
column | number | 2 (vertical 3) | Label/value pairs per row |
bordered | boolean attr | false | Ruled table with cell borders + tinted label column |
size | 'default' | 'small' | 'large' | default | Cell padding scale |
layout | 'horizontal' | 'vertical' | horizontal | Label : value side-by-side, or label stacked over value |
label | string (on children) | — | Each child's label attribute names its item |
span | number (items/children) | 1 | How many columns the item spans |
(children) | slot | — | Each child's content is the item value (when not using items) |
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-descriptions'; // registers <aha-descriptions>
Agent feed for this component (absolute, fetchable anywhere): descriptions.agent.json · descriptions.md · descriptions.llms.txt
When to use
When to use
- Descriptions — read-only label/value facts about one entity (a plan, an account)
- Form — the same fields need to be edited
- Table — the same fields across many records
Labels are sentence case nouns — 'Billing cycle', not 'BILLING CYCLE'. Keep to the facts that matter; a long grid reads like a form nobody can fill in.
Surfaces
dashboard settings
Spec
Container border 1px #E3E3E3 · radius 8px · bg #FFFFFF · Title padding 12/16 · 15/22 SemiBold #1A1A1A · divider #F1F1F1 · Label cell SemiBold #4A4A4A · bordered → bg #F7F7F7 + tinted column · Value cell #1A1A1A · 14/22 · rows/cells ruled #F1F1F1 · Column N label/value pairs flow per row; an item spans several (default 2 · vertical 3) · Bordered ruled table — cell borders #F1F1F1 + tinted label column; plain = row dividers only · Size padding scale — default 12/16 · small 8/12 · large 16/20 · Layout horizontal (label : value) · vertical (label over value)