Description list
Labeled fields for the details of a single record.
- Invoice
- INV-2046
- Billed to
- Sahel Logistics
- Contact
- Moussa Traoré
- Issued
- Sep 22, 2026
- Due
- Oct 6, 2026
- Total
- $2,940.00
import {
DescriptionDetails,
DescriptionList,
DescriptionTerm,
} from '@/components/description-list'
export default function Example() {
return (
<DescriptionList>
<DescriptionTerm>Invoice</DescriptionTerm>
<DescriptionDetails>INV-2046</DescriptionDetails>
<DescriptionTerm>Billed to</DescriptionTerm>
<DescriptionDetails>Sahel Logistics</DescriptionDetails>
<DescriptionTerm>Contact</DescriptionTerm>
<DescriptionDetails>Moussa Traoré</DescriptionDetails>
<DescriptionTerm>Issued</DescriptionTerm>
<DescriptionDetails>Sep 22, 2026</DescriptionDetails>
<DescriptionTerm>Due</DescriptionTerm>
<DescriptionDetails>Oct 6, 2026</DescriptionDetails>
<DescriptionTerm>Total</DescriptionTerm>
<DescriptionDetails>$2,940.00</DescriptionDetails>
</DescriptionList>
)
}<script setup lang="ts">
import DescriptionDetails from '@/components/description-details.vue'
import DescriptionList from '@/components/description-list.vue'
import DescriptionTerm from '@/components/description-term.vue'
</script>
<template>
<DescriptionList>
<DescriptionTerm>Invoice</DescriptionTerm>
<DescriptionDetails>INV-2046</DescriptionDetails>
<DescriptionTerm>Billed to</DescriptionTerm>
<DescriptionDetails>Sahel Logistics</DescriptionDetails>
<DescriptionTerm>Contact</DescriptionTerm>
<DescriptionDetails>Moussa Traoré</DescriptionDetails>
<DescriptionTerm>Issued</DescriptionTerm>
<DescriptionDetails>Sep 22, 2026</DescriptionDetails>
<DescriptionTerm>Due</DescriptionTerm>
<DescriptionDetails>Oct 6, 2026</DescriptionDetails>
<DescriptionTerm>Total</DescriptionTerm>
<DescriptionDetails>$2,940.00</DescriptionDetails>
</DescriptionList>
</template>Installation
Copy these files into the folder where you keep your components. They import each other with relative paths, so the folder can live anywhere. The packages they rely on are listed on the Installation page.
import clsx from 'clsx'
const row = 'sm:border-t sm:border-zinc-950/5 sm:py-3 dark:sm:border-white/5'
export function DescriptionList({ className, ...props }: React.ComponentPropsWithoutRef<'dl'>) {
return (
<dl
{...props}
className={clsx(className, 'grid grid-cols-1 sm:grid-cols-[min(50%,--spacing(80))_minmax(0,1fr)] text-base/6 sm:text-sm/6')}
/>
)
}
export function DescriptionTerm({ className, ...props }: React.ComponentPropsWithoutRef<'dt'>) {
return (
<dt
{...props}
className={clsx(
className,
row,
'col-start-1 border-t border-zinc-950/5 pt-3 text-zinc-500 first:border-none dark:border-white/5 dark:text-zinc-400'
)}
/>
)
}
export function DescriptionDetails({ className, ...props }: React.ComponentPropsWithoutRef<'dd'>) {
return <dd {...props} className={clsx(className, row, 'min-w-0 pt-1 pb-3 wrap-break-word text-zinc-950 sm:nth-2:border-none dark:text-white')} />
}<template>
<dl class="grid grid-cols-1 sm:grid-cols-[min(50%,--spacing(80))_minmax(0,1fr)] text-base/6 sm:text-sm/6">
<slot />
</dl>
</template>Component API
| Prop | Default | Description |
|---|---|---|
DescriptionListrenders a <dl> element | ||
| This component does not expose any component-specific props. | ||
DescriptionTermrenders a <dt> element | ||
| This component does not expose any component-specific props. | ||
DescriptionDetailsrenders a <dd> element | ||
| This component does not expose any component-specific props. | ||
Usage
Reach for a description list on the page of one record, where every value needs its label. When people compare several records side by side, a table serves them better. Keep labels short and consistent across records, so the same field always sits in the same place.
On small screens each value drops under its label. From the sm breakpoint up, labels move to a left column that takes half the width, capped at 20rem. A thin line separates the pairs at every size.
API key details
Alternate DescriptionTerm and DescriptionDetails inside DescriptionList, one pair per field, in the order people check them:
- Name
- Billing sync
- Created by
- Aïcha Diallo
- Permissions
- Read invoices, write payouts
- Last used
- 2 minutes ago
import {
DescriptionDetails,
DescriptionList,
DescriptionTerm,
} from '@/components/description-list'
export default function Example() {
return (
<DescriptionList>
<DescriptionTerm>Name</DescriptionTerm>
<DescriptionDetails>Billing sync</DescriptionDetails>
<DescriptionTerm>Created by</DescriptionTerm>
<DescriptionDetails>Aïcha Diallo</DescriptionDetails>
<DescriptionTerm>Permissions</DescriptionTerm>
<DescriptionDetails>Read invoices, write payouts</DescriptionDetails>
<DescriptionTerm>Last used</DescriptionTerm>
<DescriptionDetails>2 minutes ago</DescriptionDetails>
</DescriptionList>
)
}<script setup lang="ts">
import DescriptionDetails from '@/components/description-details.vue'
import DescriptionList from '@/components/description-list.vue'
import DescriptionTerm from '@/components/description-term.vue'
</script>
<template>
<DescriptionList>
<DescriptionTerm>Name</DescriptionTerm>
<DescriptionDetails>Billing sync</DescriptionDetails>
<DescriptionTerm>Created by</DescriptionTerm>
<DescriptionDetails>Aïcha Diallo</DescriptionDetails>
<DescriptionTerm>Permissions</DescriptionTerm>
<DescriptionDetails>Read invoices, write payouts</DescriptionDetails>
<DescriptionTerm>Last used</DescriptionTerm>
<DescriptionDetails>2 minutes ago</DescriptionDetails>
</DescriptionList>
</template>Composition
One group per topic
On a long record, split the fields into groups and title each one with a Subheading, so people can jump to the part they came for:
Payout account
- Account holder
- Northwind SARL
- Bank
- Ecobank Senegal
- Account number
- •••• 4821
- Schedule
- Every Tuesday
<Subheading>Payout account</Subheading>
<DescriptionList className="mt-4">
<DescriptionTerm>Account holder</DescriptionTerm>
<DescriptionDetails>Northwind SARL</DescriptionDetails>
<DescriptionTerm>Bank</DescriptionTerm>
<DescriptionDetails>Ecobank Senegal</DescriptionDetails>
<DescriptionTerm>Account number</DescriptionTerm>
<DescriptionDetails>•••• 4821</DescriptionDetails>
<DescriptionTerm>Schedule</DescriptionTerm>
<DescriptionDetails>Every Tuesday</DescriptionDetails>
</DescriptionList><Subheading>Payout account</Subheading>
<DescriptionList class="mt-4">
<DescriptionTerm>Account holder</DescriptionTerm>
<DescriptionDetails>Northwind SARL</DescriptionDetails>
<DescriptionTerm>Bank</DescriptionTerm>
<DescriptionDetails>Ecobank Senegal</DescriptionDetails>
<DescriptionTerm>Account number</DescriptionTerm>
<DescriptionDetails>•••• 4821</DescriptionDetails>
<DescriptionTerm>Schedule</DescriptionTerm>
<DescriptionDetails>Every Tuesday</DescriptionDetails>
</DescriptionList>Values beyond plain text
DescriptionDetails takes any content. Show a state with a Badge, a value to copy with Code, and a person with an Avatar beside the name:
- URL
https://api.sahel-logistics.com/hooks/billing- Status
- Live
- Events
- invoice.paid, invoice.overdue
- Owner
Wilo Ahadi
<DescriptionList>
<DescriptionTerm>URL</DescriptionTerm>
<DescriptionDetails>
<Code>https://api.sahel-logistics.com/hooks/billing</Code>
</DescriptionDetails>
<DescriptionTerm>Status</DescriptionTerm>
<DescriptionDetails>
<Badge color="emerald" dot>Live</Badge>
</DescriptionDetails>
<DescriptionTerm>Events</DescriptionTerm>
<DescriptionDetails>invoice.paid, invoice.overdue</DescriptionDetails>
<DescriptionTerm>Owner</DescriptionTerm>
<DescriptionDetails>
<div className="flex items-center gap-2">
<Avatar src={owner.avatarUrl} className="size-5" />
{owner.name}
</div>
</DescriptionDetails>
</DescriptionList><DescriptionList>
<DescriptionTerm>URL</DescriptionTerm>
<DescriptionDetails>
<Code>https://api.sahel-logistics.com/hooks/billing</Code>
</DescriptionDetails>
<DescriptionTerm>Status</DescriptionTerm>
<DescriptionDetails>
<Badge color="emerald" dot>Live</Badge>
</DescriptionDetails>
<DescriptionTerm>Events</DescriptionTerm>
<DescriptionDetails>invoice.paid, invoice.overdue</DescriptionDetails>
<DescriptionTerm>Owner</DescriptionTerm>
<DescriptionDetails>
<div class="flex items-center gap-2">
<Avatar :src="owner.avatarUrl" class="size-5" />
{{ owner.name }}
</div>
</DescriptionDetails>
</DescriptionList>