Skip to content
38

Description List

Label and value pairs for detail pages, like an invoice, a user or a server. Terms sit beside their values when there is room and stack on narrow screens, with optional columns, dividers and icons.

Example

Installation

npx shadcn@latest add https://hirael.com/r/description-list.json

Usage

import {
  DescriptionList,
  DescriptionListItem,
  DescriptionListTerm,
  DescriptionListDetails,
} from "@/components/description-list"

Paths assume the default @/ alias from your components.json. The example above shows the parts composed.

API

<DescriptionList />

+ native element props
PropTypeDefault
orientation

`horizontal` puts each term beside its value once the list is wide enough, and stacks them on narrow containers. `vertical` always stacks.

DescriptionListOrientation'horizontal'
columns

Items per row. Extra columns appear only once the container is wide enough.

1 | 2 | 31
divided

Draw a hairline between items.

booleanfalse

<DescriptionListItem />

+ native element props

No props of its own; forwards everything to the underlying element.

<DescriptionListTerm />

+ native element props

No props of its own; forwards everything to the underlying element.

<DescriptionListDetails />

+ native element props

No props of its own; forwards everything to the underlying element.

Component source

import * as React from 'react';

import { cn } from '@/lib/utils';

export type DescriptionListOrientation = 'horizontal' | 'vertical';

export interface DescriptionListProps extends React.ComponentProps<'dl'> {
  /**
   * `horizontal` puts each term beside its value once the list is wide enough,
   * and stacks them on narrow containers. `vertical` always stacks.
   */
  orientation?: DescriptionListOrientation;
  /** Items per row. Extra columns appear only once the container is wide enough. */
  columns?: 1 | 2 | 3;
  /** Draw a hairline between items. */
  divided?: boolean;
}

const COLUMN_CLASS = {
  1: '',
  2: '@xl/description-list:grid-cols-2',
  3: '@xl/description-list:grid-cols-2 @4xl/description-list:grid-cols-3',
} as const;

const DescriptionList = ({
  orientation = 'horizontal',
  columns = 1,
  divided = false,
  className,
  ...props
}: DescriptionListProps) => {
  return (
    <div data-slot="description-list-container" className="@container/description-list w-full">
      <dl
        data-slot="description-list"
        data-orientation={orientation}
        data-divided={divided || undefined}
        className={cn(
          'group/description-list grid gap-x-8 text-sm',
          divided ? 'gap-y-0' : 'gap-y-4',
          COLUMN_CLASS[columns],
          className,
        )}
        {...props}
      />
    </div>
  );
};

const DescriptionListItem = ({ className, ...props }: React.ComponentProps<'div'>) => {
  return (
    <div
      data-slot="description-list-item"
      className={cn(
        'grid min-w-0 content-start gap-1',
        'group-data-[orientation=horizontal]/description-list:@md/description-list:grid-cols-[minmax(0,var(--description-list-term-width,11rem))_minmax(0,1fr)] group-data-[orientation=horizontal]/description-list:@md/description-list:gap-4',
        'group-data-divided/description-list:border-b group-data-divided/description-list:border-border group-data-divided/description-list:py-3 group-data-divided/description-list:last:border-b-0',
        className,
      )}
      {...props}
    />
  );
};

const DescriptionListTerm = ({ className, ...props }: React.ComponentProps<'dt'>) => {
  return (
    <dt
      data-slot="description-list-term"
      className={cn('flex min-w-0 items-center gap-2 text-muted-foreground [&_svg]:size-4 [&_svg]:shrink-0', className)}
      {...props}
    />
  );
};

const DescriptionListDetails = ({ className, ...props }: React.ComponentProps<'dd'>) => {
  return (
    <dd
      data-slot="description-list-details"
      className={cn('flex min-w-0 flex-wrap items-center gap-2 font-medium text-foreground', className)}
      {...props}
    />
  );
};

export { DescriptionList, DescriptionListItem, DescriptionListTerm, DescriptionListDetails };

Shipped