# Details List

Accessible, responsive, copy-paste starter for details panels with 2 variants.

## Details List

Source: CoreAI.

Baseline label/value layout with text values.

[Download source](/coreai-design-system/source/examples/templates-details-list--default.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { Link } from "@coreai-ds/react-components";
import * as React from 'react';
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { mergeClasses } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";

type DetailsItem = {
    key: React.Key;
    label: React.ReactNode;
    /** The value to show. If there is no value, leave this detail out of the list. */
    value: React.ReactNode;
};

interface DetailsListProps extends Omit<React.ComponentPropsWithoutRef<'dl'>, 'children'> {
    items: DetailsItem[];
    itemClassName?: string;
    labelClassName?: string;
    valueClassName?: string;
}

// ─── Styles ──────────────────────────────────────────────────────────────────
const useStyles = makeStyles({
    // ── Root container ─────────────────────────────────────────────────────────
    root: {
        display: 'flex',
        flexDirection: 'column',
        rowGap: tokens.spacingVerticalL,
        margin: 0,
        padding: 0,
        width: '100%',
    },
    // ── Row layout ─────────────────────────────────────────────────────────────
    item: {
        display: 'flex',
        flexDirection: 'column',
        rowGap: tokens.spacingVerticalXXS,
    },
    // ── Label / value text ────────────────────────────────────────────────────
    label: {
        margin: 0,
    },
    value: {
        margin: 0,
    },
});

// ─── Component ────────────────────────────────────────────────────────────────
function DetailsList({ items, className, itemClassName, labelClassName, valueClassName, ...rest }: DetailsListProps) {
    const styles = useStyles();
    return (<dl {...rest} className={mergeClasses('fui-DetailsList', styles.root, className)}>
      {items.map((item) => (<div key={item.key} className={mergeClasses('fui-DetailsList__item', styles.item, itemClassName)}>
          <dt className={mergeClasses('fui-DetailsList__label', styles.label, labelClassName)}>
            {typeof item.label === 'string' || typeof item.label === 'number' ? (<Text preset="bodySStrong" foreground={2}>
                {item.label}
              </Text>) : (item.label)}
          </dt>
          <dd className={mergeClasses('fui-DetailsList__value', styles.value, valueClassName)}>
            {typeof item.value === 'string' || typeof item.value === 'number' ? (<Text preset="body" foreground={1}>
                {item.value}
              </Text>) : (item.value)}
          </dd>
        </div>))}
    </dl>);
}

export const Default = () => {
    const items = [
        { key: 'name', label: 'Name', value: 'John Smith' },
        {
            key: 'email',
            label: 'Email',
            value: <Link href="mailto:john.smith@example.com">john.smith@example.com</Link>,
        },
        { key: 'role', label: 'Role', value: 'Software Engineer' },
        { key: 'department', label: 'Department', value: 'Engineering' },
        { key: 'location', label: 'Location', value: 'Seattle, WA' },
    ];
    return <DetailsList items={items}/>;
};

export default Default;
```

## Implementation

CoreAI 0.12.0; Fluent 9.74.9.

[Setup and dependencies](/coreai-design-system/guides/Package.md).

Copy this template into your app. It is not an npm export. Adapt actions and navigation to your product.

## With Custom Classes

Source: CoreAI.

Uses class name props to arrange details in horizontal rows within grouped card sections.
The values can contain interactive content such as links and buttons.

[Download source](/coreai-design-system/source/examples/templates-details-list--with-custom-classes.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { Link } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { Card } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import * as React from 'react';
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { mergeClasses } from "@coreai-ds/react-components";
import { Divider } from "@coreai-ds/react-components";

type DetailsItem = {
    key: React.Key;
    label: React.ReactNode;
    /** The value to show. If there is no value, leave this detail out of the list. */
    value: React.ReactNode;
};

interface DetailsListProps extends Omit<React.ComponentPropsWithoutRef<'dl'>, 'children'> {
    items: DetailsItem[];
    itemClassName?: string;
    labelClassName?: string;
    valueClassName?: string;
}

// ─── Styles ──────────────────────────────────────────────────────────────────
const useStyles = makeStyles({
    // ── Root container ─────────────────────────────────────────────────────────
    root: {
        display: 'flex',
        flexDirection: 'column',
        rowGap: tokens.spacingVerticalL,
        margin: 0,
        padding: 0,
        width: '100%',
    },
    // ── Row layout ─────────────────────────────────────────────────────────────
    item: {
        display: 'flex',
        flexDirection: 'column',
        rowGap: tokens.spacingVerticalXXS,
    },
    // ── Label / value text ────────────────────────────────────────────────────
    label: {
        margin: 0,
    },
    value: {
        margin: 0,
    },
});

// ─── Component ────────────────────────────────────────────────────────────────
function DetailsList({ items, className, itemClassName, labelClassName, valueClassName, ...rest }: DetailsListProps) {
    const styles = useStyles();
    return (<dl {...rest} className={mergeClasses('fui-DetailsList', styles.root, className)}>
      {items.map((item) => (<div key={item.key} className={mergeClasses('fui-DetailsList__item', styles.item, itemClassName)}>
          <dt className={mergeClasses('fui-DetailsList__label', styles.label, labelClassName)}>
            {typeof item.label === 'string' || typeof item.label === 'number' ? (<Text preset="bodySStrong" foreground={2}>
                {item.label}
              </Text>) : (item.label)}
          </dt>
          <dd className={mergeClasses('fui-DetailsList__value', styles.value, valueClassName)}>
            {typeof item.value === 'string' || typeof item.value === 'number' ? (<Text preset="body" foreground={1}>
                {item.value}
              </Text>) : (item.value)}
          </dd>
        </div>))}
    </dl>);
}

export const WithCustomClasses = () => {
    const modelFacts = [
        { key: 'provider', label: 'Model provider', value: 'Anthropic' },
        { key: 'type', label: 'Type', value: 'Messages' },
        { key: 'lifecycle', label: 'Lifecycle', value: 'Generally Available' },
        { key: 'hosted', label: 'Hosted on', value: 'Azure' },
    ];
    const inputOutputFacts = [
        { key: 'input', label: 'Input type', value: 'text, image, code' },
        { key: 'output', label: 'Output type', value: 'text, image, code' },
    ];
    const capacityFacts = [
        { key: 'context', label: 'Context window', value: '1000k' },
        { key: 'tokens', label: 'Token limits', value: '128k output' },
    ];
    const actionFacts = [
        {
            key: 'pricing',
            label: 'Pricing',
            value: (<Link href="https://azure.microsoft.com/pricing" target="_blank" external>
            View pricing
          </Link>),
        },
        {
            key: 'availability',
            label: 'Availability',
            value: <Button appearance="outline">View availability</Button>,
        },
    ];
    const slotClassNameProps = {
        itemClassName: 'details-list-example__item',
        labelClassName: 'details-list-example__label',
        valueClassName: 'details-list-example__value',
    };
    const styles = /* css */ `
       .details-list-example__card {
        width: 356px;
        max-width: 100%;
        padding: var(--spacingVerticalXXL);
        row-gap: var(--spacingVerticalL);
      }

       .details-list-example__heading {
        margin: 0;
      }

       .details-list-example__section {
        row-gap: var(--spacingVerticalS);
      }

       .details-list-example__item {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: center;
        column-gap: var(--spacingHorizontalL);
      }

       .details-list-example__label {
        min-width: 0;
      }

       .details-list-example__value {
        min-width: 0;
        text-align: end;
      }
    `;
    return (<>
        <style>{styles}</style>
        <Card className="details-list-example__card">
          <Text as="h2" preset="heading4" foreground={1} className="details-list-example__heading">
            Quick facts
          </Text>
          <DetailsList items={modelFacts} className="details-list-example__section" {...slotClassNameProps}/>
          <Divider />
          <DetailsList items={inputOutputFacts} className="details-list-example__section" {...slotClassNameProps}/>
          <Divider />
          <DetailsList items={capacityFacts} className="details-list-example__section" {...slotClassNameProps}/>
          <Divider />
          <DetailsList items={actionFacts} className="details-list-example__section" {...slotClassNameProps}/>
        </Card>
      </>);
};

export default WithCustomClasses;
```

## Template source: DetailsList.tsx

[Download DetailsList.tsx](/coreai-design-system/source/templates/details-list/DetailsList.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

/**
 * Templates / Details List
 *
 * Starter scaffold for building a label-value details panel with CoreAI
 * primitives. Keep the semantic <dl>/<dt>/<dd> structure, replace the sample
 * items with your own data, and optionally customize class hooks.
 *
 * Displays label-value pairs in a compact, readable layout.
 * Useful for user profiles, resource metadata, and summary panels.
 *
 * Copy-paste starting point — not an importable component.
 */

import * as React from 'react';
import { makeStyles, mergeClasses, Text, tokens } from '@coreai-ds/react-components';

export type DetailsItem = {
  key: React.Key;
  label: React.ReactNode;
  /** The value to show. If there is no value, leave this detail out of the list. */
  value: React.ReactNode;
};

// ─── Styles ──────────────────────────────────────────────────────────────────

const useStyles = makeStyles({
  // ── Root container ─────────────────────────────────────────────────────────
  root: {
    display: 'flex',
    flexDirection: 'column',
    rowGap: tokens.spacingVerticalL,
    margin: 0,
    padding: 0,
    width: '100%',
  },

  // ── Row layout ─────────────────────────────────────────────────────────────
  item: {
    display: 'flex',
    flexDirection: 'column',
    rowGap: tokens.spacingVerticalXXS,
  },

  // ── Label / value text ────────────────────────────────────────────────────
  label: {
    margin: 0,
  },
  value: {
    margin: 0,
  },
});

export interface DetailsListProps extends Omit<React.ComponentPropsWithoutRef<'dl'>, 'children'> {
  items: DetailsItem[];
  itemClassName?: string;
  labelClassName?: string;
  valueClassName?: string;
}

// ─── Component ────────────────────────────────────────────────────────────────

export function DetailsList({
  items,
  className,
  itemClassName,
  labelClassName,
  valueClassName,
  ...rest
}: DetailsListProps) {
  const styles = useStyles();

  return (
    <dl {...rest} className={mergeClasses('fui-DetailsList', styles.root, className)}>
      {items.map((item) => (
        <div
          key={item.key}
          className={mergeClasses('fui-DetailsList__item', styles.item, itemClassName)}
        >
          <dt className={mergeClasses('fui-DetailsList__label', styles.label, labelClassName)}>
            {typeof item.label === 'string' || typeof item.label === 'number' ? (
              <Text preset="bodySStrong" foreground={2}>
                {item.label}
              </Text>
            ) : (
              item.label
            )}
          </dt>
          <dd className={mergeClasses('fui-DetailsList__value', styles.value, valueClassName)}>
            {typeof item.value === 'string' || typeof item.value === 'number' ? (
              <Text preset="body" foreground={1}>
                {item.value}
              </Text>
            ) : (
              item.value
            )}
          </dd>
        </div>
      ))}
    </dl>
  );
}
```