All components
Data List
Label and value pairs for metadata panels, with subtle and bold label emphasis.
- Status
- Active
- Region
- eu-west-1
- Plan
- Pro
- Created
- Mar 12, 2026
12345678910111213141516171819202122232425import { DataList } from "#components/ui/base-ui/data-list.tsx";
const details = [ ["Status", "Active"], ["Region", "eu-west-1"], ["Plan", "Pro"],];
export function Example() { return ( // variant/size/orientation resolve once on Root; parts inherit them via // context and expose data-* attributes — the root renders a semantic <dl> <DataList.Root variant="subtle" size="md" orientation="horizontal"> {details.map(([label, value]) => ( <DataList.Item key={label}> <DataList.ItemLabel>{label}</DataList.ItemLabel> <DataList.ItemValue>{value}</DataList.ItemValue> </DataList.Item> ))} </DataList.Root> );}
// horizontal label column width comes from a custom property:// <DataList.ItemLabel style={styles.labelW}> with { "--label-width": "90px" }Variants
- Status
- Active
- Region
- eu-west-1
- Plan
- Pro
- Created
- Mar 12, 2026
- Status
- Active
- Region
- eu-west-1
- Plan
- Pro
- Created
- Mar 12, 2026
Sizes
- Status
- Active
- Region
- eu-west-1
- Plan
- Pro
- Created
- Mar 12, 2026
- Status
- Active
- Region
- eu-west-1
- Plan
- Pro
- Created
- Mar 12, 2026
- Status
- Active
- Region
- eu-west-1
- Plan
- Pro
- Created
- Mar 12, 2026
Install
1npx stylexblocks add data-listSource
components/ui/base-ui/data-list.tsx
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184import * as stylex from "@stylexjs/stylex";import { createSlotRecipeContext } from "#lib/base-ui/create-slot-recipe-context.tsx";import { defineSlotRecipe } from "#lib/recipe-props.ts";import { fontSizes } from '@stylexblocks/ui/tokens/font-sizes.stylex.ts'import { fontWeights } from '@stylexblocks/ui/tokens/font-weights.stylex.ts'import { lineHeights } from '@stylexblocks/ui/tokens/line-heights.stylex.ts'import { semanticColors } from '@stylexblocks/ui/semantic-tokens/colors.stylex.ts'import { spacing } from '@stylexblocks/ui/tokens/spacing.stylex.ts'
const dataListItemLabel = stylex.create({ base: { color: semanticColors.fgMuted, display: 'flex', alignItems: 'center', gap: spacing._1, },})
const dataListItemLabelVariants = stylex.create({ subtle: { color: semanticColors.fgMuted, }, bold: { fontWeight: fontWeights.medium, },})
const dataListItemLabelOrientations = stylex.create({ horizontal: { minWidth: 'var(--label-width, 120px)', },})
const dataListItemValue = stylex.create({ base: { display: 'flex', minWidth: 0, flex: 1, },})
const dataListItemValueVariants = stylex.create({ bold: { color: semanticColors.fgMuted, },})
const dataListRoot = stylex.create({ base: {},})
const dataListRootSizes = stylex.create({ sm: { gap: spacing._3, }, md: { gap: spacing._4, }, lg: { gap: spacing._5, },})
const dataListRootOrientations = stylex.create({ horizontal: { display: 'flex', flexDirection: 'column', }, vertical: { display: 'flex', flexDirection: 'column', },})
const dataListItem = stylex.create({ base: {},})
const dataListItemSizes = stylex.create({ sm: { fontSize: fontSizes.xs, lineHeight: lineHeights.xs, }, md: { fontSize: fontSizes.sm, lineHeight: lineHeights.sm, }, lg: { fontSize: fontSizes.md, lineHeight: lineHeights.md, },})
const dataListItemOrientations = stylex.create({ horizontal: { display: 'inline-flex', alignItems: 'center', gap: spacing._4, }, vertical: { display: 'flex', flexDirection: 'column', gap: spacing._1, },})
export type DataListOrientation = keyof typeof dataListItemLabelOrientations
export type DataListSize = keyof typeof dataListRootSizes
export type DataListVariant = keyof typeof dataListItemLabelVariants
// The parts render definition-list semantics (<dl>/<dt>/<dd>); the preflight// does not zero UA list margins, so the component carries its own resets.const dataListLocal = stylex.create({ dl: { marginBlock: 0 }, dd: { marginInlineStart: 0 },});
// defineSlotRecipe validates the shape at compile time: default values must// exist in the axis maps, and slot keys must be `styles` or a declared axisconst dataListSlotRecipe = defineSlotRecipe({ slots: { root: { styles: dataListRoot, sizes: dataListRootSizes, orientations: dataListRootOrientations, }, item: { styles: dataListItem, sizes: dataListItemSizes, orientations: dataListItemOrientations, }, itemLabel: { styles: dataListItemLabel, variants: dataListItemLabelVariants, orientations: dataListItemLabelOrientations, }, itemValue: { styles: dataListItemValue, variants: dataListItemValueVariants }, }, defaultVariants: { size: "md", orientation: "horizontal", variant: "subtle" },});
/** * DataList — recipe and component colocated in one file. `<DataList.Root * variant size orientation>` resolves the recipe once and every part * inherits it through context; each part composes via `render`. The sparse * maps (label orientation styles only horizontal, value styles only bold) * resolve through explicit resolvers. */const { withProvider, withContext } = createSlotRecipeContext(dataListSlotRecipe);
export const DataList = { Root: withProvider( "dl", (v) => [ dataListRoot.base, dataListRootSizes[v.size], dataListRootOrientations[v.orientation], dataListLocal.dl, ], "DataListRoot", ), Item: withContext("div", "item", "DataListItem"), ItemLabel: withContext( "dt", (v) => [ dataListItemLabel.base, dataListItemLabelVariants[v.variant], v.orientation === "horizontal" && dataListItemLabelOrientations.horizontal, ], "DataListItemLabel", ), ItemValue: withContext( "dd", (v) => [ dataListItemValue.base, v.variant === "bold" && dataListItemValueVariants.bold, dataListLocal.dd, ], "DataListItemValue", ),};