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.jsonUsage
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| Prop | Type | Default |
|---|---|---|
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' |
columnsItems per row. Extra columns appear only once the container is wide enough. | 1 | 2 | 3 | 1 |
dividedDraw a hairline between items. | boolean | false |
<DescriptionListItem />
+ native element propsNo props of its own; forwards everything to the underlying element.
<DescriptionListTerm />
+ native element propsNo props of its own; forwards everything to the underlying element.
<DescriptionListDetails />
+ native element propsNo 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