Skip to content
  1. Records
  2. Description list

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

PropDefaultDescription
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>