Skip to content
design
Components

Description list

Terms and their values as a list, stacked, in aligned columns or along a row.

On this page
Name
Althea
State
Underway
MMSI
244 630 123From the ship station license; call sign PBAQ7.
Flag
Netherlands, home port Den Helder
Length overall
14.2 m; beam 4.3 m; draft 2.1 m
Insurance
Pantaenius Yacht Insurance, policy 2026-NL-0441872, cover for European waters to 30 June 2027
A vessel's particulars in aligned columns, with icons, a state badge, a hint and a long value cut to one line.
Code
import { Badge } from "@bosunkit/components/badge";
import { DescriptionList, type DescriptionListItem } from "@bosunkit/components/description-list";
import { Anchor, Flag, Radio, Ruler, Ship, ShieldCheck } from "lucide-react";
import type { ReactElement } from "react";

export const description: string =
  "SV Althea's particulars in aligned columns: an icon before each term, a badge for her state, a hint under the " +
  "MMSI, and the insurer's long policy name cut to one line with the whole name on hover or focus.";

const PARTICULARS: readonly DescriptionListItem[] = [
  { term: "Name", value: "Althea", icon: <Ship /> },
  { term: "State", value: <Badge variant="green">Underway</Badge>, icon: <Anchor /> },
  {
    term: "MMSI",
    value: "244 630 123",
    icon: <Radio />,
    hint: "From the ship station license; call sign PBAQ7.",
  },
  { term: "Flag", value: "Netherlands, home port Den Helder", icon: <Flag /> },
  { term: "Length overall", value: "14.2 m; beam 4.3 m; draft 2.1 m", icon: <Ruler /> },
  {
    term: "Insurance",
    value: "Pantaenius Yacht Insurance, policy 2026-NL-0441872, cover for European waters to 30 June 2027",
    icon: <ShieldCheck />,
  },
];

export default function Showcase(): ReactElement {
  return (
    <div style={{ width: "100%", maxWidth: 480 }}>
      <DescriptionList items={PARTICULARS} truncate />
    </div>
  );
}

A description list shows terms and their values: a vessel's particulars, a leg's figures, a service record. It is a <dl>, each pair a <dt> and a <dd>, so a screen reader reads each value with its term. Terms are small mono capitals in the dim text color and values use tabular figures. A value is text or a node, such as a badge or a link; each pair can take an icon before its term and a hint under its value. A live value from an instrument is a reading, which shows its source, age and integrity; a description list is for text.

01Read as pairsThe list is a <dl>, so each value is read with its term, and the terms line up so the eye runs down the values.
02The layout fits the spaceColumns where there is width, stacked in a narrow panel, inline for a summary under a title.
03Nothing lost to a cutA value cut to one line shows its whole text on hover or focus, and only a cut value takes focus.

Examples

Columns

columns, the default, puts the terms in a column as wide as the longest term, and every value starts at the same edge. On a phone, a screen up to the 40em breakpoint (640 px at 16 px), the columns stack, each term over its value, so a long value takes the screen's width rather than what the longest term leaves it.

From
Brest
To
A Coruña
Distance
412 NM
Departure
06:00 UTC, 14 October
The terms in a column as wide as the longest, every value starting at one edge.
Code
import { DescriptionList, type DescriptionListItem } from "@bosunkit/components/description-list";
import type { ReactElement } from "react";

export const description: string = "The terms in a column as wide as the longest, every value starting at one edge.";

const LEG: readonly DescriptionListItem[] = [
  { term: "From", value: "Brest" },
  { term: "To", value: "A Coruña" },
  { term: "Distance", value: "412 NM" },
  { term: "Departure", value: "06:00 UTC, 14 October" },
];

export default function Columns(): ReactElement {
  return <DescriptionList items={LEG} />;
}

Stacked

stacked puts each term over its value, for a narrow panel or values that run long.

Last service
Palma, 2 March 2026, 1 214 engine hours
Next service
At 1 714 engine hours, or by 2 March 2027
Workshop
Varadero Palma, Moll Vell
Each term over its value, for a narrow panel or values that run long.
Code
import { DescriptionList, type DescriptionListItem } from "@bosunkit/components/description-list";
import type { ReactElement } from "react";

export const description: string = "Each term over its value, for a narrow panel or values that run long.";

const SERVICE: readonly DescriptionListItem[] = [
  { term: "Last service", value: "Palma, 2 March 2026, 1 214 engine hours" },
  { term: "Next service", value: "At 1 714 engine hours, or by 2 March 2027" },
  { term: "Workshop", value: "Varadero Palma, Moll Vell" },
];

export default function Stacked(): ReactElement {
  return (
    <div style={{ width: "100%", maxWidth: 320 }}>
      <DescriptionList items={SERVICE} layout="stacked" />
    </div>
  );
}

Inline

inline runs the pairs along a row and wraps them where it ends, for a short summary under a title.

Crew
4
Watch
Marta, to 16:00 UTC
Logged
98 NM
Engine
1 412 hr
The pairs along a row, wrapping where it ends, for a summary under a title.
Code
import { DescriptionList, type DescriptionListItem } from "@bosunkit/components/description-list";
import type { ReactElement } from "react";

export const description: string = "The pairs along a row, wrapping where it ends, for a summary under a title.";

const SUMMARY: readonly DescriptionListItem[] = [
  { term: "Crew", value: "4" },
  { term: "Watch", value: "Marta, to 16:00 UTC" },
  { term: "Logged", value: "98 NM" },
  { term: "Engine", value: "1 412 hr" },
];

export default function Inline(): ReactElement {
  return <DescriptionList items={SUMMARY} layout="inline" />;
}

Icons and hints

An icon before a term is decorative and hidden from assistive technology. A hint sits under the value in the same <dd>, so it is read with the value.

Diesel
212 L of 400 LSounded by hand at 08:00 UTC.
Water
365 L of 600 LTanks 2 and 3, from the tank senders.
An icon before each term, hidden from assistive technology, and a hint under a value saying where it comes from.
Code
import { DescriptionList, type DescriptionListItem } from "@bosunkit/components/description-list";
import { Droplets, Fuel } from "lucide-react";
import type { ReactElement } from "react";

export const description: string =
  "An icon before each term, hidden from assistive technology, and a hint under a value saying where it comes from.";

const TANKS: readonly DescriptionListItem[] = [
  { term: "Diesel", value: "212 L of 400 L", icon: <Fuel />, hint: "Sounded by hand at 08:00 UTC." },
  { term: "Water", value: "365 L of 600 L", icon: <Droplets />, hint: "Tanks 2 and 3, from the tank senders." },
];

export default function IconsAndHints(): ReactElement {
  return <DescriptionList items={TANKS} />;
}

Values that are nodes

A value can be a badge, a link or any other node; it is drawn as it is.

Registration
Valid until March 2029
Liferaft
Service overdue by 12 days
Values that are nodes: a badge for a state and a link to a record.
Code
import { Badge } from "@bosunkit/components/badge";
import { DescriptionList, type DescriptionListItem } from "@bosunkit/components/description-list";
import type { ReactElement } from "react";

export const description: string = "Values that are nodes: a badge for a state and a link to a record.";

const DOCUMENTS: readonly DescriptionListItem[] = [
  { term: "Registration", value: <Badge variant="green">Valid until March 2029</Badge> },
  { term: "Liferaft", value: <Badge variant="amber">Service overdue by 12 days</Badge> },
  { term: "Survey", value: <a href="#survey-2025">Survey report, May 2025</a> },
];

export default function NodeValues(): ReactElement {
  return <DescriptionList items={DOCUMENTS} />;
}

Truncated

truncate keeps each text value to one line, cut with an ellipsis where it does not fit. A value that is cut takes focus and shows its whole text in a tooltip on hover or focus; a value that fits stays plain text. Values that are nodes are not cut. Nothing the crew need to act safely belongs in a cut value, since its end shows only on hover or focus.

Anchorage
Baie de Morgat, off the lifeboat slip, 9 m of water over sand and mud
Holding
Good
Shelter
From west through north to east; open to the south and a swell round Cap de la Chèvre
Long text values cut to one line; a cut value takes focus and shows its whole text in a tooltip.
Code
import { DescriptionList, type DescriptionListItem } from "@bosunkit/components/description-list";
import type { ReactElement } from "react";

export const description: string =
  "Long text values cut to one line; a cut value takes focus and shows its whole text in a tooltip.";

const ANCHORAGE: readonly DescriptionListItem[] = [
  { term: "Anchorage", value: "Baie de Morgat, off the lifeboat slip, 9 m of water over sand and mud" },
  { term: "Holding", value: "Good" },
  { term: "Shelter", value: "From west through north to east; open to the south and a swell round Cap de la Chèvre" },
];

export default function Truncate(): ReactElement {
  return (
    <div style={{ width: "100%", maxWidth: 360 }}>
      <DescriptionList items={ANCHORAGE} truncate />
    </div>
  );
}

Props

PropTypeDefaultDescription
itemsrequiredreadonly DescriptionListItem[]–The pairs, in order.
layoutDescriptionListLayout | undefined"columns"How the pairs are laid out: columns (the default) puts the terms in a column whose width is the longest term, each value beside its term, and stacks them on a screen (bk-screen) narrower than 700 px; stacked puts each term over its value; inline runs the pairs along a row and wraps them.
truncateboolean | undefinedfalseKeeps each text value to one line, cut with an ellipsis where it does not fit. A value that is cut can take focus and shows its whole text in a tooltip on hover or focus. Values that are nodes are drawn as they are.
classNamestring | undefined–Classes added to the list.
testIdstring | undefined–Becomes data-testid on the list; each pair's row is ${testId}--row.
refRef<HTMLDListElement> | undefined–The <dl> element.
Do
Distance
4.8 NM
ETA Audierne
10:34 UTC
Write each value with its unit, as a reading shows it.
Don't
Distance
4.8
ETA Audierne
10:34
Don't leave the unit out. A distance of 4.8 reads as nautical miles to one crew member and kilometers to another, and a time without its zone can be an hour out.
  • Reading: a live value with its source, age and integrity.
  • Card: the surface a list of particulars usually sits on.
  • Section heading: the heading over a group of pairs.
  • Tooltip: the tooltip a cut value opens.