Details List
View .mdAccessible, responsive, copy-paste starter for details panels with 2 variants.
Details List
Loading interactive example. Full source is available below.
View example source
// 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.
Copy this template into your app. It is not an npm export. Adapt actions and navigation to your product.
With Custom Classes
Loading interactive example. Full source is available below.
// 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
Copy this file into your app. Do not import this template from the package.
// 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>
);
}