Default

Loading interactive example. Full source is available below.

View example source
Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as React from 'react';
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

export const Default = () => {
    type Item = {
        file: {
            label: string;
            icon: React.JSX.Element;
        };
        author: {
            label: string;
            status: PresenceBadgeStatus;
        };
        lastUpdated: {
            label: string;
            timestamp: number;
        };
        lastUpdate: {
            label: string;
            icon: React.JSX.Element;
        };
    };
    const items: Item[] = [
        {
            file: { label: 'Meeting notes', icon: <DocumentRegular /> },
            author: { label: 'Max Mustermann', status: 'available' },
            lastUpdated: { label: '7h ago', timestamp: 1 },
            lastUpdate: { label: 'You edited this', icon: <EditRegular /> },
        },
        {
            file: { label: 'Thursday presentation', icon: <FolderRegular /> },
            author: { label: 'Erika Mustermann', status: 'busy' },
            lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
            lastUpdate: { label: 'You recently opened this', icon: <OpenRegular /> },
        },
        {
            file: { label: 'Training recording', icon: <VideoRegular /> },
            author: { label: 'John Doe', status: 'away' },
            lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
            lastUpdate: { label: 'You recently opened this', icon: <OpenRegular /> },
        },
        {
            file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
            author: { label: 'Jane Doe', status: 'offline' },
            lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
            lastUpdate: { label: 'You shared this in a Teams chat', icon: <PeopleRegular /> },
        },
    ];
    const columns: TableColumnDefinition<Item>[] = [
        createTableColumn<Item>({
            columnId: 'file',
            compare: (first, second) => first.file.label.localeCompare(second.file.label),
            renderHeaderCell: () => 'File',
            renderCell: (item) => (<TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>),
        }),
        createTableColumn<Item>({
            columnId: 'author',
            compare: (first, second) => first.author.label.localeCompare(second.author.label),
            renderHeaderCell: () => 'Author',
            renderCell: (item) => (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
            {item.author.label}
          </TableCellLayout>),
        }),
        createTableColumn<Item>({
            columnId: 'lastUpdated',
            compare: (first, second) => first.lastUpdated.timestamp - second.lastUpdated.timestamp,
            renderHeaderCell: () => 'Last updated',
            renderCell: (item) => item.lastUpdated.label,
        }),
        createTableColumn<Item>({
            columnId: 'lastUpdate',
            compare: (first, second) => first.lastUpdate.label.localeCompare(second.lastUpdate.label),
            renderHeaderCell: () => 'Last update',
            renderCell: (item) => (<TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>),
        }),
    ];
    const styles = /* css */ `
      .data-grid-default-example {
        min-width: 550px;
      }
    `;
    return (<>
        <style>{styles}</style>
        <DataGrid className="data-grid-default-example" items={items} columns={columns} sortable selectionMode="multiselect" getRowId={(item) => item.file.label} focusMode="composite">
          <DataGridHeader>
            <DataGridRow selectionCell={{
            checkboxIndicator: { 'aria-label': 'Select all rows' },
        }}>
              {({ renderHeaderCell }) => (<DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>)}
            </DataGridRow>
          </DataGridHeader>
          <DataGridBody<Item>>
            {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{
                checkboxIndicator: { 'aria-label': 'Select row' },
            }}>
                {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
              </DataGridRow>)}
          </DataGridBody>
        </DataGrid>
      </>);
};

export default Default;

Resources

Best practices

Do

  • Use a hyphen (-) for any empty values.
  • Left-align textual data within DataGrid cells.
  • Left-align categorical numeric data within DataGrid cells.
  • Use the cell link variant instead of the cell text variant to help users distinguish links from other text content in adjoining cells.
  • Use a subtle badge with a status icon instead of an outline badge.
  • Consider a sticky header when a DataGrid has more than 20 items per page.
  • Consider a sticky header when values may be ambiguous without column headers.
  • Consider a sticky header when users need to act on resources upon selection.
  • Consider a sticky header when a DataGrid has more than five columns or sortable columns.

Don't

  • Allow text to wrap to more than three rows.
  • Leave too much white space after cell content.
  • Use a sticky header in DataGrids without actions in the header.
  • Use a sticky header for continuous scrolling.
  • Place interactive elements inside DataGrid header cells.

Behavior and states

  • DataGrids don’t require reflow by default, but designers can set column priorities for smaller screens.
  • Less critical columns may be hidden first; essential ones should always remain visible.
  • If all columns are important, keep them all and allow horizontal scrolling instead.
API referenceGenerated CoreAI prop and type summaries

API

Generated CoreAI prop summaries, not replacement type declarations. Most native DOM/event and ARIA props are omitted. ? means optional; JSDoc shows defaults, deprecations, and conditional requirements. Defaults assume the standard CoreAI provider.

DataGrid API

interface DataGridProps {
  as?: "div" | "table";

  children?: any;

  className?: string;

  /**
   * CSS-only per-column flexbox overrides, keyed by `columnId` (same convention as
   * `columnSizingOptions`). Automatically picked up by this package's `DataGridHeaderCell`
   * and `DataGridCell` wrappers — no need to read `columnId` off the render prop yourself.
   *
   * Intended for static/non-resizable layouts. Not supported in combination with
   * `resizableColumns` — that takes precedence when both are set.
   */
  columnFlexOptions?: DataGridColumnFlexOptions;

  /**
   * Table columns
   */
  columns: TableColumnDefinition<any>[];

  /**
   * Options for column resizing, specific for each column
   */
  columnSizingOptions?: TableColumnSizingOptions;

  /**
   * For column resizing. Allows for a container size to be adjusted by a number of pixels, to make
   * sure the columns don't overflow the table.
   * By default, this value is calculated internally based on other props, but can be overriden.
   */
  containerWidthOffset?: number;

  /**
   * Used in uncontrolled mode to set initial selected items on mount
   */
  defaultSelectedItems?: Iterable<SelectionItemId>;

  /**
   * Used in uncontrolled mode to set initial sort column and direction on mount
   */
  defaultSortState?: SortState;

  /**
   * How focus navigation will work in the datagrid
   * @default cell
   */
  focusMode?: "none" | "cell" | "row_unstable" | "composite";

  getRowId?: ((item: any) => TableRowId);

  items: any[];

  /**
   * Render all table elements as divs instead of semantic table elements
   * Using divs no longer uses `display: table` layout but `display: flex`
   * @default false
   */
  noNativeElements?: boolean;

  /**
   * A callback triggered when a column is resized.
   */
  onColumnResize?: ((e: MouseEvent | TouchEvent | KeyboardEvent, data: { columnId: TableColumnId; width: number; }) => void);

  onSelectionChange?: ((e: MouseEvent<Element, MouseEvent> | KeyboardEvent<Element>, data: OnSelectionChangeData) => void);

  onSortChange?: ((e: MouseEvent<Element, MouseEvent>, sortState: SortState) => void);

  ref?: Ref<HTMLDivElement>;

  /**
   * Enables column resizing
   */
  resizableColumns?: boolean;

  /**
   * Custom options for column resizing.
   */
  resizableColumnsOptions?: { autoFitColumns?: boolean; };

  /**
   * Used to control selected items
   */
  selectedItems?: Iterable<SelectionItemId>;

  /**
   * Row appearance when selected
   * @default brand
   */
  selectionAppearance?: "none" | "brand" | "neutral";

  /**
   * Enables row selection and sets the selection mode
   * @default false
   */
  selectionMode?: "multiselect" | "single";

  /**
   * Affects the sizes of all table subcomponents
   * @default medium
   */
  size?: "small" | "medium" | "extra-small";

  /**
   * Whether the table is sortable
   * @default false
   */
  sortable?: boolean;

  /**
   * Used to control sorting
   */
  sortState?: SortState;

  style?: CSSProperties;

  /**
   * Enables subtle selection style
   * @default false
   */
  subtleSelection?: boolean;
}

DataGridBody API

DataGridBody component

interface DataGridBodyProps {
  as?: "div" | "tbody";

  /**
   * Render function for rows
   */
  children: RowRenderFunction<unknown>;

  className?: string;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;
}

DataGridCell API

interface DataGridCellProps {
  as?: "div" | "td";

  children?: any;

  className?: string;

  /**
   * Used when there are nested focusble elements inside a focusable cell
   * - `group`: Enter keypress moves focus inside the cell, focus is trapped inside the cell until Escape keypress
   * - `cell`: The cell is focusable - if there are focusable elements in the cell use `group`
   * - `none`: The cell is not focusable
   * @default cell
   */
  focusMode?: "none" | "cell" | "group";

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;
}

DataGridHeader API

DataGridHeader component

interface DataGridHeaderProps {
  as?: "div" | "thead";

  children?: any;

  className?: string;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;
}

DataGridHeaderCell API

interface DataGridHeaderCellProps {
  as?: "div" | "th";

  /**
   * aside content for anything that should be after main content of the table header cell
   */
  aside?: WithSlotShorthandValue<{ as?: "span"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & { ref?: ((instance: HTMLSpanElement | null) => void) | RefObject<HTMLSpanElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  /**
   * Button handles correct narration and interactions for sorting;
   */
  button?: NonNullable<WithSlotShorthandValue<ARIAButtonSlotProps> | null>;

  children?: any;

  className?: string;

  /**
   * Used when there are nested focusble elements inside a focusable cell
   * - `group`: Enter keypress moves focus inside the cell, focus is trapped inside the cell until Escape keypress
   * - `cell`: The cell is focusable - if there are focusable elements in the cell use `group`
   * - `none`: The cell is not focusable
   * @default cell
   */
  focusMode?: "none" | "cell" | "group";

  ref?: Ref<HTMLDivElement>;

  /**
   * @default undefined
   */
  sortDirection?: "ascending" | "descending";

  sortIcon?: WithSlotShorthandValue<{ as?: "span"; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & { ref?: ((instance: HTMLSpanElement | null) => void) | RefObject<HTMLSpanElement> | null; }, "children"> & { children?: any; }> | null | undefined;

  style?: CSSProperties;
}

DataGridRow API

DataGridRow component

interface DataGridRowProps {
  /**
   * A table row can have different variants. These appearances are
   * intended to be used with selection.
   * @default none
   */
  appearance?: "none" | "brand" | "neutral";

  as?: "div" | "tr";

  children: CellRenderFunction<unknown>;

  className?: string;

  ref?: Ref<HTMLDivElement>;

  /**
   * When selection is enabled on the
   */
  selectionCell?: WithSlotShorthandValue<TableSelectionCellProps & RefAttributes<HTMLDivElement>> | null;

  style?: CSSProperties;
}

DataGridSelectionCell API

DataGridSelectionCell component

interface DataGridSelectionCellProps {
  as?: "div" | "td";

  /**
   * Selection indicator if selection type is checkbox
   */
  checkboxIndicator?: (Omit<ComponentProps<Partial<CheckboxSlots>, "input">, "defaultChecked" | "onChange" | "size" | "checked"> & { checked?: boolean | "mixed"; children?: undefined; defaultChecked?: boolean | "mixed"; labelPosition?: "before" | "after" | undefined; onChange?: ((ev: ChangeEvent<HTMLInputElement>, data: CheckboxOnChangeData) => void) | undefined; shape?: "circular" | "square" | undefined; size?: "medium" | "large" | undefined; } & RefAttributes<HTMLInputElement>) | null | undefined;

  /**
   * @default false
   */
  checked?: boolean | "mixed";

  children?: any;

  className?: string;

  /**
   * Completely hides the selection cell
   * @deprecated cells should never use hidden, since doing so breaks table structure and screen reader navigation. Use `invisible` instead.
   */
  hidden?: boolean;

  /**
   * Hides the selection cell visually but takes up the same space
   * @default false
   */
  invisible?: boolean;

  /**
   * Selection indicator if selection type is radio
   */
  radioIndicator?: (Omit<ComponentProps<Partial<RadioSlots>, "input">, "onChange" | "size"> & { value?: string; labelPosition?: "below" | "after"; disabled?: boolean | undefined; onChange?: ((ev: ChangeEvent<HTMLInputElement>, data: RadioOnChangeData) => void) | undefined; } & RefAttributes<HTMLInputElement>) | null | undefined;

  ref?: Ref<HTMLDivElement>;

  style?: CSSProperties;

  /**
   * Only visible when checked or the parent row is hovered/focused
   * @default false
   */
  subtle?: boolean;

  /**
   * A table can have two kinds of selection modes.
   * @default checkbox
   */
  type?: "checkbox" | "radio";
}

Implementation

CoreAI 0.12.0; Fluent 9.74.9.

Setup and dependencies.

Import components from @coreai-ds/react-components. CoreAI guidance above takes precedence over API demonstration examples.

Composite Navigation

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";
import * as React from 'react';

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type LastUpdateCell = {
    label: string;
    icon: JSXElement;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
    lastUpdate: LastUpdateCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
        lastUpdate: {
            label: 'You edited this',
            icon: <EditRegular />,
        },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
        lastUpdate: {
            label: 'You shared this in a Teams chat',
            icon: <PeopleRegular />,
        },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return <TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        renderHeaderCell: () => {
            return 'Author';
        },
        renderCell: item => {
            return (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdated',
        renderHeaderCell: () => {
            return 'Last updated';
        },
        renderCell: item => {
            return item.lastUpdated.label;
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdate',
        renderHeaderCell: () => {
            return 'Last update';
        },
        renderCell: item => {
            return <TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>;
        },
    }),
];

export const CompositeNavigation = (): JSXElement => {
    return (<DataGrid selectionMode="multiselect" items={items} columns={columns} focusMode="composite" style={{ minWidth: '550px' }}>
      <DataGridHeader>
        <DataGridRow selectionCell={{ checkboxIndicator: { 'aria-label': 'Select all rows' } }}>
          {({ renderHeaderCell }) => <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>}
        </DataGridRow>
      </DataGridHeader>
      <DataGridBody<Item>>
        {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{ checkboxIndicator: { 'aria-label': 'Select row' } }}>
            {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
          </DataGridRow>)}
      </DataGridBody>
    </DataGrid>);
};

export default CompositeNavigation;

Custom Row Id

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import type { TableRowId } from "@coreai-ds/react-components";
import type { DataGridProps } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import { Checkbox } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import type { TableRowData } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type LastUpdateCell = {
    label: string;
    icon: JSXElement;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
    lastUpdate: LastUpdateCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
        lastUpdate: {
            label: 'You edited this',
            icon: <EditRegular />,
        },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
        lastUpdate: {
            label: 'You shared this in a Teams chat',
            icon: <PeopleRegular />,
        },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        compare: (a, b) => {
            return a.file.label.localeCompare(b.file.label);
        },
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return <TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        compare: (a, b) => {
            return a.author.label.localeCompare(b.author.label);
        },
        renderHeaderCell: () => {
            return 'Author';
        },
        renderCell: item => {
            return (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdated',
        compare: (a, b) => {
            return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
        },
        renderHeaderCell: () => {
            return 'Last updated';
        },
        renderCell: item => {
            return item.lastUpdated.label;
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdate',
        compare: (a, b) => {
            return a.lastUpdate.label.localeCompare(b.lastUpdate.label);
        },
        renderHeaderCell: () => {
            return 'Last update';
        },
        renderCell: item => {
            return <TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>;
        },
    }),
];

export const CustomRowId = (): JSXElement => {
    const [selectedRows, setSelectedRows] = React.useState(new Set<TableRowId>(['Thursday presentation']));
    const onSelectionChange: DataGridProps['onSelectionChange'] = (e, data) => {
        setSelectedRows(data.selectedItems);
    };
    return (<>
      <ul>
        {items.map(item => (<li key={item.file.label}>
            <Checkbox label={item.file.label} checked={selectedRows.has(item.file.label)}/>
          </li>))}
      </ul>

      <DataGrid items={items} columns={columns} selectionMode="multiselect" selectedItems={selectedRows} onSelectionChange={onSelectionChange} getRowId={item => item.file.label} style={{ minWidth: '550px' }}>
        <DataGridHeader>
          <DataGridRow selectionCell={{ checkboxIndicator: { 'aria-label': 'Select all rows' } }}>
            {({ renderHeaderCell }: TableColumnDefinition<Item>) => (<DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>)}
          </DataGridRow>
        </DataGridHeader>
        <DataGridBody>
          {({ item, rowId }: TableRowData<Item>) => (<DataGridRow key={rowId} selectionCell={{ checkboxIndicator: { 'aria-label': 'Select row' } }}>
              {({ renderCell }: TableColumnDefinition<Item>) => <DataGridCell>{renderCell(item)}</DataGridCell>}
            </DataGridRow>)}
        </DataGridBody>
      </DataGrid>
    </>);
};

export default CustomRowId;

Data Grid Accordion

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as React from 'react';
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { Accordion } from "@coreai-ds/react-components";
import { AccordionItem } from "@coreai-ds/react-components";
import { AccordionHeader } from "@coreai-ds/react-components";
import { AccordionPanel } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { ArrowDownloadRegular } from "@fluentui/react-icons";

export const DataGridAccordion = () => {
    type Item = {
        file: {
            label: string;
            icon: React.JSX.Element;
        };
        author: {
            label: string;
            status: PresenceBadgeStatus;
        };
        lastUpdated: {
            label: string;
            timestamp: number;
        };
        lastUpdate: {
            label: string;
            icon: React.JSX.Element;
        };
    };
    const items: Item[] = [
        {
            file: { label: 'Meeting notes', icon: <DocumentRegular /> },
            author: { label: 'Max Mustermann', status: 'available' },
            lastUpdated: { label: '7h ago', timestamp: 1 },
            lastUpdate: { label: 'You edited this', icon: <EditRegular /> },
        },
        {
            file: { label: 'Thursday presentation', icon: <FolderRegular /> },
            author: { label: 'Erika Mustermann', status: 'busy' },
            lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
            lastUpdate: { label: 'You recently opened this', icon: <OpenRegular /> },
        },
        {
            file: { label: 'Training recording', icon: <VideoRegular /> },
            author: { label: 'John Doe', status: 'away' },
            lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
            lastUpdate: { label: 'You recently opened this', icon: <OpenRegular /> },
        },
        {
            file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
            author: { label: 'Jane Doe', status: 'offline' },
            lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
            lastUpdate: { label: 'You shared this in a Teams chat', icon: <PeopleRegular /> },
        },
    ];
    const columns: TableColumnDefinition<Item>[] = [
        createTableColumn<Item>({
            columnId: 'file',
            compare: (first, second) => first.file.label.localeCompare(second.file.label),
            renderHeaderCell: () => 'File',
            renderCell: (item) => (<TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>),
        }),
        createTableColumn<Item>({
            columnId: 'author',
            compare: (first, second) => first.author.label.localeCompare(second.author.label),
            renderHeaderCell: () => 'Author',
            renderCell: (item) => (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
            {item.author.label}
          </TableCellLayout>),
        }),
        createTableColumn<Item>({
            columnId: 'lastUpdated',
            compare: (first, second) => first.lastUpdated.timestamp - second.lastUpdated.timestamp,
            renderHeaderCell: () => 'Last updated',
            renderCell: (item) => item.lastUpdated.label,
        }),
        createTableColumn<Item>({
            columnId: 'lastUpdate',
            compare: (first, second) => first.lastUpdate.label.localeCompare(second.lastUpdate.label),
            renderHeaderCell: () => 'Last update',
            renderCell: (item) => (<TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>),
        }),
    ];
    const styles = /* css */ `
      .data-grid-accordion-example {
        background-color: var(--colorNeutralBackground1);
        border: var(--strokeWidthThin) solid var(--colorNeutralStroke2);
        border-radius: var(--borderRadiusXLarge);
        display: flex;
        flex-direction: column;
        overflow: hidden;
      }
      .data-grid-accordion-example__header-button.fui-AccordionHeader__button {
        padding-left: var(--spacingHorizontalM);
        padding-right: var(--spacingHorizontalM);
      }
      .data-grid-accordion-example__panel {
        margin: 0;
      }
      .data-grid-accordion-example__grid {
        border-left-width: 0;
        border-radius: 0;
        border-right-width: 0;
      }
      .data-grid-accordion-example__footer {
        align-items: center;
        column-gap: var(--spacingHorizontalM);
        display: flex;
        justify-content: space-between;
        padding: var(--spacingVerticalS) var(--spacingHorizontalM);
      }
    `;
    return (<>
        <style>{styles}</style>
        <Accordion className="data-grid-accordion-example" collapsible defaultOpenItems="files">
          <AccordionItem value="files">
            <AccordionHeader button={{ className: 'data-grid-accordion-example__header-button' }}>
              Shared documents
            </AccordionHeader>
            <AccordionPanel className="data-grid-accordion-example__panel">
              <DataGrid className="data-grid-accordion-example__grid" items={items} columns={columns} sortable selectionMode="multiselect" getRowId={(item) => item.file.label} focusMode="composite">
                <DataGridHeader>
                  <DataGridRow selectionCell={{
            checkboxIndicator: { 'aria-label': 'Select all rows' },
        }}>
                    {({ renderHeaderCell }) => (<DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>)}
                  </DataGridRow>
                </DataGridHeader>
                <DataGridBody<Item>>
                  {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{
                checkboxIndicator: { 'aria-label': 'Select row' },
            }}>
                      {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
                    </DataGridRow>)}
                </DataGridBody>
              </DataGrid>

              <div className="data-grid-accordion-example__footer">
                <Text preset="bodyStrong">Showing 4 of 128 items</Text>
                <Button appearance="transparent" icon={<ArrowDownloadRegular />}>
                  Export all
                </Button>
              </div>
            </AccordionPanel>
          </AccordionItem>
        </Accordion>
      </>);
};

export default DataGridAccordion;

Data Grid Card

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as React from 'react';
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { Text } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { ArrowDownloadRegular } from "@fluentui/react-icons";

export const DataGridCard = () => {
    type Item = {
        file: {
            label: string;
            icon: React.JSX.Element;
        };
        author: {
            label: string;
            status: PresenceBadgeStatus;
        };
        lastUpdated: {
            label: string;
            timestamp: number;
        };
        lastUpdate: {
            label: string;
            icon: React.JSX.Element;
        };
    };
    const items: Item[] = [
        {
            file: { label: 'Meeting notes', icon: <DocumentRegular /> },
            author: { label: 'Max Mustermann', status: 'available' },
            lastUpdated: { label: '7h ago', timestamp: 1 },
            lastUpdate: { label: 'You edited this', icon: <EditRegular /> },
        },
        {
            file: { label: 'Thursday presentation', icon: <FolderRegular /> },
            author: { label: 'Erika Mustermann', status: 'busy' },
            lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
            lastUpdate: { label: 'You recently opened this', icon: <OpenRegular /> },
        },
        {
            file: { label: 'Training recording', icon: <VideoRegular /> },
            author: { label: 'John Doe', status: 'away' },
            lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
            lastUpdate: { label: 'You recently opened this', icon: <OpenRegular /> },
        },
        {
            file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
            author: { label: 'Jane Doe', status: 'offline' },
            lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
            lastUpdate: { label: 'You shared this in a Teams chat', icon: <PeopleRegular /> },
        },
    ];
    const columns: TableColumnDefinition<Item>[] = [
        createTableColumn<Item>({
            columnId: 'file',
            compare: (first, second) => first.file.label.localeCompare(second.file.label),
            renderHeaderCell: () => 'File',
            renderCell: (item) => (<TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>),
        }),
        createTableColumn<Item>({
            columnId: 'author',
            compare: (first, second) => first.author.label.localeCompare(second.author.label),
            renderHeaderCell: () => 'Author',
            renderCell: (item) => (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
            {item.author.label}
          </TableCellLayout>),
        }),
        createTableColumn<Item>({
            columnId: 'lastUpdated',
            compare: (first, second) => first.lastUpdated.timestamp - second.lastUpdated.timestamp,
            renderHeaderCell: () => 'Last updated',
            renderCell: (item) => item.lastUpdated.label,
        }),
        createTableColumn<Item>({
            columnId: 'lastUpdate',
            compare: (first, second) => first.lastUpdate.label.localeCompare(second.lastUpdate.label),
            renderHeaderCell: () => 'Last update',
            renderCell: (item) => (<TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>),
        }),
    ];
    const styles = /* css */ `
      .data-grid-card-example {
        background-color: var(--colorNeutralBackground1);
        border: var(--strokeWidthThin) solid var(--colorNeutralStroke2);
        border-radius: var(--borderRadiusXLarge);
        display: flex;
        flex-direction: column;
        overflow: hidden;
      }
      .data-grid-card-example__header {
        display: flex;
        flex-direction: column;
        padding: var(--spacingVerticalM) var(--spacingHorizontalM);
        row-gap: var(--spacingVerticalXXS);
      }
      .data-grid-card-example__grid {
        border-left-width: 0;
        border-radius: 0;
        border-right-width: 0;
      }
      .data-grid-card-example__footer {
        align-items: center;
        column-gap: var(--spacingHorizontalM);
        display: flex;
        justify-content: space-between;
        padding: var(--spacingVerticalS) var(--spacingHorizontalM);
      }
    `;
    return (<>
        <style>{styles}</style>
        <div className="data-grid-card-example">
          <div className="data-grid-card-example__header">
            <Text preset="heading4">Shared documents</Text>
            <Text preset="bodyS">4 files · Updated 7h ago</Text>
          </div>

          <DataGrid className="data-grid-card-example__grid" items={items} columns={columns} sortable selectionMode="multiselect" getRowId={(item) => item.file.label} focusMode="composite">
            <DataGridHeader>
              <DataGridRow selectionCell={{
            checkboxIndicator: { 'aria-label': 'Select all rows' },
        }}>
                {({ renderHeaderCell }) => (<DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>)}
              </DataGridRow>
            </DataGridHeader>
            <DataGridBody<Item>>
              {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{
                checkboxIndicator: { 'aria-label': 'Select row' },
            }}>
                  {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
                </DataGridRow>)}
            </DataGridBody>
          </DataGrid>

          <div className="data-grid-card-example__footer">
            <Text preset="bodyStrong">Showing 4 of 128 items</Text>
            <Button appearance="transparent" icon={<ArrowDownloadRegular />}>
              Export all
            </Button>
          </div>
        </div>
      </>);
};

export default DataGridCard;

Flex Options

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as React from 'react';
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

export const FlexOptions = () => {
    type Item = {
        file: {
            label: string;
            icon: React.JSX.Element;
        };
        author: {
            label: string;
            status: PresenceBadgeStatus;
        };
        lastUpdated: {
            label: string;
            timestamp: number;
        };
        lastUpdate: {
            label: string;
            icon: React.JSX.Element;
        };
    };
    const items: Item[] = [
        {
            file: { label: 'Meeting notes', icon: <DocumentRegular /> },
            author: { label: 'Max Mustermann', status: 'available' },
            lastUpdated: { label: '7h ago', timestamp: 1 },
            lastUpdate: { label: 'You edited this', icon: <EditRegular /> },
        },
        {
            file: { label: 'Thursday presentation', icon: <FolderRegular /> },
            author: { label: 'Erika Mustermann', status: 'busy' },
            lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
            lastUpdate: { label: 'You recently opened this', icon: <OpenRegular /> },
        },
        {
            file: { label: 'Training recording', icon: <VideoRegular /> },
            author: { label: 'John Doe', status: 'away' },
            lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
            lastUpdate: { label: 'You recently opened this', icon: <OpenRegular /> },
        },
        {
            file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
            author: { label: 'Jane Doe', status: 'offline' },
            lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
            lastUpdate: { label: 'You shared this in a Teams chat', icon: <PeopleRegular /> },
        },
    ];
    const columns: TableColumnDefinition<Item>[] = [
        createTableColumn<Item>({
            columnId: 'file',
            compare: (first, second) => first.file.label.localeCompare(second.file.label),
            renderHeaderCell: () => 'File',
            renderCell: (item) => (<TableCellLayout truncate media={item.file.icon}>
            {item.file.label}
          </TableCellLayout>),
        }),
        createTableColumn<Item>({
            columnId: 'author',
            compare: (first, second) => first.author.label.localeCompare(second.author.label),
            renderHeaderCell: () => 'Author',
            renderCell: (item) => (<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>),
        }),
        createTableColumn<Item>({
            columnId: 'lastUpdated',
            compare: (first, second) => first.lastUpdated.timestamp - second.lastUpdated.timestamp,
            renderHeaderCell: () => 'Last updated',
            renderCell: (item) => <TableCellLayout truncate>{item.lastUpdated.label}</TableCellLayout>,
        }),
        createTableColumn<Item>({
            columnId: 'lastUpdate',
            compare: (first, second) => first.lastUpdate.label.localeCompare(second.lastUpdate.label),
            renderHeaderCell: () => 'Last update',
            renderCell: (item) => (<TableCellLayout truncate media={item.lastUpdate.icon}>
            {item.lastUpdate.label}
          </TableCellLayout>),
        }),
    ];
    const styles = /* css */ `
      .data-grid-flex-options-example {
        overflow-x: auto;
      }
    `;
    return (<>
        <style>{styles}</style>
        <DataGrid className="data-grid-flex-options-example" items={items} columns={columns} sortable getRowId={(item) => item.file.label} selectionMode="multiselect" columnFlexOptions={{
            file: { flexGrow: 1, flexShrink: 1, flexBasis: 0, minWidth: 0 },
            author: { flexGrow: 0.1, flexShrink: 0, flexBasis: 60 },
            lastUpdated: { flexGrow: 0.6, flexShrink: 1, flexBasis: 0, minWidth: '20ch' },
            lastUpdate: { flexGrow: 1, flexShrink: 1, flexBasis: 0, minWidth: 180 },
        }}>
          <DataGridHeader>
            <DataGridRow selectionCell={{ checkboxIndicator: { 'aria-label': 'Select all rows' } }}>
              {({ renderHeaderCell }) => (<DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>)}
            </DataGridRow>
          </DataGridHeader>
          <DataGridBody<Item>>
            {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{ checkboxIndicator: { 'aria-label': 'Select row' } }}>
                {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
              </DataGridRow>)}
          </DataGridBody>
        </DataGrid>
      </>);
};

export default FlexOptions;

Focusable Elements In Cells

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { EditRegular } from "@fluentui/react-icons";
import { Menu } from "@coreai-ds/react-components";
import { MenuTrigger } from "@coreai-ds/react-components";
import { MoreHorizontalRegular } from "@fluentui/react-icons";
import { MenuPopover } from "@coreai-ds/react-components";
import { MenuList } from "@coreai-ds/react-components";
import { MenuItem } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { OpenRegular } from "@fluentui/react-icons";
import { DeleteRegular } from "@fluentui/react-icons";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";
import type { TableColumnId } from "@coreai-ds/react-components";
import type { DataGridCellFocusMode } from "@coreai-ds/react-components";
import * as React from 'react';

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        compare: (a, b) => {
            return a.file.label.localeCompare(b.file.label);
        },
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return <TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        renderHeaderCell: () => {
            return (<>
          Author
          <Button appearance="transparent" aria-label="Edit" icon={<EditRegular />}/>
          <Menu positioning={{ autoSize: true }}>
            <MenuTrigger disableButtonEnhancement>
              <Button appearance="transparent" icon={<MoreHorizontalRegular />} aria-label="More options"/>
            </MenuTrigger>

            <MenuPopover>
              <MenuList>
                <MenuItem>Delete column</MenuItem>
                <MenuItem>Create new author</MenuItem>
              </MenuList>
            </MenuPopover>
          </Menu>
        </>);
        },
        renderCell: item => {
            return (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'singleAction',
        renderHeaderCell: () => {
            return 'Single action';
        },
        renderCell: () => {
            return <Button icon={<OpenRegular />}>Open</Button>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'actions',
        renderHeaderCell: () => {
            return 'Actions';
        },
        renderCell: () => {
            return (<>
          <Button aria-label="Edit" icon={<EditRegular />}/>
          <Button aria-label="Delete" icon={<DeleteRegular />}/>
        </>);
        },
    }),
];

const getCellFocusMode = (columnId: TableColumnId): DataGridCellFocusMode => {
    switch (columnId) {
        case 'singleAction':
            return 'none';
        case 'actions':
            return 'group';
        default:
            return 'cell';
    }
};

export const FocusableElementsInCells = (): JSXElement => {
    return (<DataGrid items={items} columns={columns} sortable selectionMode="multiselect" getRowId={item => item.file.label} onSelectionChange={(e, data) => console.log(data)} style={{ minWidth: '550px' }}>
      <DataGridHeader>
        <DataGridRow selectionCell={{ checkboxIndicator: { 'aria-label': 'Select all rows' } }}>
          {({ columnId, renderHeaderCell }) => (<DataGridHeaderCell focusMode={columnId === 'author' ? 'group' : undefined}>
              {renderHeaderCell()}
            </DataGridHeaderCell>)}
        </DataGridRow>
      </DataGridHeader>
      <DataGridBody<Item>>
        {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{ checkboxIndicator: { 'aria-label': 'Select row' } }}>
            {({ renderCell, columnId }) => (<DataGridCell focusMode={getCellFocusMode(columnId)}>{renderCell(item)}</DataGridCell>)}
          </DataGridRow>)}
      </DataGridBody>
    </DataGrid>);
};

export default FocusableElementsInCells;

Multiple Select

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { DataGrid } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type LastUpdateCell = {
    label: string;
    icon: JSXElement;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
    lastUpdate: LastUpdateCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
        lastUpdate: {
            label: 'You edited this',
            icon: <EditRegular />,
        },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
        lastUpdate: {
            label: 'You shared this in a Teams chat',
            icon: <PeopleRegular />,
        },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        compare: (a, b) => {
            return a.file.label.localeCompare(b.file.label);
        },
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return <TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        compare: (a, b) => {
            return a.author.label.localeCompare(b.author.label);
        },
        renderHeaderCell: () => {
            return 'Author';
        },
        renderCell: item => {
            return (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdated',
        compare: (a, b) => {
            return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
        },
        renderHeaderCell: () => {
            return 'Last updated';
        },
        renderCell: item => {
            return item.lastUpdated.label;
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdate',
        compare: (a, b) => {
            return a.lastUpdate.label.localeCompare(b.lastUpdate.label);
        },
        renderHeaderCell: () => {
            return 'Last update';
        },
        renderCell: item => {
            return <TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>;
        },
    }),
];

export const MultipleSelect = (): JSXElement => {
    const defaultSelectedItems = React.useMemo(() => new Set([1]), []);
    return (<DataGrid items={items} columns={columns} selectionMode="multiselect" defaultSelectedItems={defaultSelectedItems} style={{ minWidth: '550px' }}>
      <DataGridHeader>
        <DataGridRow selectionCell={{ checkboxIndicator: { 'aria-label': 'Select all rows' } }}>
          {({ renderHeaderCell }) => <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>}
        </DataGridRow>
      </DataGridHeader>
      <DataGridBody<Item>>
        {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{ checkboxIndicator: { 'aria-label': 'Select row' } }}>
            {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
          </DataGridRow>)}
      </DataGridBody>
    </DataGrid>);
};

export default MultipleSelect;

Multiple Select Controlled

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import type { TableRowId } from "@coreai-ds/react-components";
import type { DataGridProps } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type LastUpdateCell = {
    label: string;
    icon: JSXElement;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
    lastUpdate: LastUpdateCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
        lastUpdate: {
            label: 'You edited this',
            icon: <EditRegular />,
        },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
        lastUpdate: {
            label: 'You shared this in a Teams chat',
            icon: <PeopleRegular />,
        },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        compare: (a, b) => {
            return a.file.label.localeCompare(b.file.label);
        },
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return <TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        compare: (a, b) => {
            return a.author.label.localeCompare(b.author.label);
        },
        renderHeaderCell: () => {
            return 'Author';
        },
        renderCell: item => {
            return (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdated',
        compare: (a, b) => {
            return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
        },
        renderHeaderCell: () => {
            return 'Last updated';
        },
        renderCell: item => {
            return item.lastUpdated.label;
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdate',
        compare: (a, b) => {
            return a.lastUpdate.label.localeCompare(b.lastUpdate.label);
        },
        renderHeaderCell: () => {
            return 'Last update';
        },
        renderCell: item => {
            return <TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>;
        },
    }),
];

export const MultipleSelectControlled = (): JSXElement => {
    const [selectedRows, setSelectedRows] = React.useState(new Set<TableRowId>([1]));
    const onSelectionChange: DataGridProps['onSelectionChange'] = (e, data) => {
        setSelectedRows(data.selectedItems);
    };
    return (<DataGrid items={items} columns={columns} selectionMode="multiselect" selectedItems={selectedRows} onSelectionChange={onSelectionChange} style={{ minWidth: '550px' }}>
      <DataGridHeader>
        <DataGridRow selectionCell={{ checkboxIndicator: { 'aria-label': 'Select all rows' } }}>
          {({ renderHeaderCell }) => <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>}
        </DataGridRow>
      </DataGridHeader>
      <DataGridBody<Item>>
        {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{ checkboxIndicator: { 'aria-label': 'Select row' } }}>
            {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
          </DataGridRow>)}
      </DataGridBody>
    </DataGrid>);
};

export default MultipleSelectControlled;

Resizable Columns (preview)

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { DataGrid } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { Menu } from "@coreai-ds/react-components";
import { MenuTrigger } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { MenuPopover } from "@coreai-ds/react-components";
import { MenuList } from "@coreai-ds/react-components";
import { MenuItem } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type LastUpdateCell = {
    label: string;
    icon: JSXElement;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
    lastUpdate: LastUpdateCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
        lastUpdate: {
            label: 'You edited this',
            icon: <EditRegular />,
        },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
        lastUpdate: {
            label: 'You shared this in a Teams chat',
            icon: <PeopleRegular />,
        },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        compare: (a, b) => {
            return a.file.label.localeCompare(b.file.label);
        },
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return (<TableCellLayout truncate media={item.file.icon}>
          {item.file.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        compare: (a, b) => {
            return a.author.label.localeCompare(b.author.label);
        },
        renderHeaderCell: () => {
            return 'Author';
        },
        renderCell: item => {
            return (<TableCellLayout truncate media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdated',
        compare: (a, b) => {
            return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
        },
        renderHeaderCell: () => {
            return 'Last updated';
        },
        renderCell: item => {
            return <TableCellLayout truncate>{item.lastUpdated.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdate',
        compare: (a, b) => {
            return a.lastUpdate.label.localeCompare(b.lastUpdate.label);
        },
        renderHeaderCell: () => {
            return 'Last update';
        },
        renderCell: item => {
            return (<TableCellLayout truncate media={item.lastUpdate.icon}>
          {item.lastUpdate.label}
        </TableCellLayout>);
        },
    }),
];

const columnSizingOptions = {
    file: {
        minWidth: 80,
        defaultWidth: 120,
    },
    author: {
        defaultWidth: 180,
        minWidth: 120,
        idealWidth: 180,
    },
};

export const ResizableColumns = (): JSXElement => {
    const refMap = React.useRef<Record<string, HTMLElement | null>>({});
    return (<div style={{ overflowX: 'auto' }}>
      <DataGrid items={items} columns={columns} sortable getRowId={item => item.file.label} selectionMode="multiselect" resizableColumns columnSizingOptions={columnSizingOptions}>
        <DataGridHeader>
          <DataGridRow selectionCell={{ checkboxIndicator: { 'aria-label': 'Select all rows' } }}>
            {({ renderHeaderCell, columnId }, dataGrid) => dataGrid.resizableColumns ? (<Menu openOnContext>
                  <MenuTrigger>
                    <DataGridHeaderCell ref={el => {
                refMap.current[columnId] = el;
            }}>
                      {renderHeaderCell()}
                    </DataGridHeaderCell>
                  </MenuTrigger>
                  <MenuPopover>
                    <MenuList>
                      <MenuItem onClick={dataGrid.columnSizing_unstable.enableKeyboardMode(columnId)}>
                        Keyboard Column Resizing
                      </MenuItem>
                    </MenuList>
                  </MenuPopover>
                </Menu>) : (<DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>)}
          </DataGridRow>
        </DataGridHeader>
        <DataGridBody<Item>>
          {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{ checkboxIndicator: { 'aria-label': 'Select row' } }}>
              {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
            </DataGridRow>)}
        </DataGridBody>
      </DataGrid>
    </div>);
};

export default ResizableColumns;

Resizable Columns Controlled

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import * as React from 'react';
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import type { TableColumnSizingOptions } from "@coreai-ds/react-components";
import type { DataGridProps } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { Menu } from "@coreai-ds/react-components";
import { MenuTrigger } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { MenuPopover } from "@coreai-ds/react-components";
import { MenuList } from "@coreai-ds/react-components";
import { MenuItem } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

export const ResizableColumnsControlled = () => {
    type Item = {
        file: {
            label: string;
            icon: React.JSX.Element;
        };
        author: {
            label: string;
            status: PresenceBadgeStatus;
        };
        lastUpdated: {
            label: string;
            timestamp: number;
        };
        lastUpdate: {
            label: string;
            icon: React.JSX.Element;
        };
    };
    const items: Item[] = [
        {
            file: { label: 'Meeting notes', icon: <DocumentRegular /> },
            author: { label: 'Max Mustermann', status: 'available' },
            lastUpdated: { label: '7h ago', timestamp: 1 },
            lastUpdate: { label: 'You edited this', icon: <EditRegular /> },
        },
        {
            file: { label: 'Thursday presentation', icon: <FolderRegular /> },
            author: { label: 'Erika Mustermann', status: 'busy' },
            lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
            lastUpdate: { label: 'You recently opened this', icon: <OpenRegular /> },
        },
        {
            file: { label: 'Training recording', icon: <VideoRegular /> },
            author: { label: 'John Doe', status: 'away' },
            lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
            lastUpdate: { label: 'You recently opened this', icon: <OpenRegular /> },
        },
        {
            file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
            author: { label: 'Jane Doe', status: 'offline' },
            lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
            lastUpdate: { label: 'You shared this in a Teams chat', icon: <PeopleRegular /> },
        },
    ];
    const columns: TableColumnDefinition<Item>[] = [
        createTableColumn<Item>({
            columnId: 'file',
            compare: (first, second) => first.file.label.localeCompare(second.file.label),
            renderHeaderCell: () => 'File',
            renderCell: (item) => (<TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>),
        }),
        createTableColumn<Item>({
            columnId: 'author',
            compare: (first, second) => first.author.label.localeCompare(second.author.label),
            renderHeaderCell: () => 'Author',
            renderCell: (item) => (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
            {item.author.label}
          </TableCellLayout>),
        }),
        createTableColumn<Item>({
            columnId: 'lastUpdated',
            compare: (first, second) => first.lastUpdated.timestamp - second.lastUpdated.timestamp,
            renderHeaderCell: () => 'Last updated',
            renderCell: (item) => item.lastUpdated.label,
        }),
        createTableColumn<Item>({
            columnId: 'lastUpdate',
            compare: (first, second) => first.lastUpdate.label.localeCompare(second.lastUpdate.label),
            renderHeaderCell: () => 'Last update',
            renderCell: (item) => (<TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>),
        }),
    ];
    const [columnSizing, setColumnSizing] = React.useState<TableColumnSizingOptions>({
        file: { minWidth: 120, defaultWidth: 240, idealWidth: 240 },
        author: { minWidth: 120, defaultWidth: 200, idealWidth: 200 },
        lastUpdated: { minWidth: 120, defaultWidth: 180, idealWidth: 180 },
        lastUpdate: { minWidth: 140, defaultWidth: 220, idealWidth: 220 },
    });
    const onColumnResize: DataGridProps['onColumnResize'] = (_event, { columnId, width }) => {
        setColumnSizing((current) => ({
            ...current,
            [columnId]: { ...current[columnId], idealWidth: width, defaultWidth: width },
        }));
    };
    const styles = /* css */ `
      .data-grid-resizable-example {
        overflow-x: auto;
      }
    `;
    return (<>
        <style>{styles}</style>
        <DataGrid className="data-grid-resizable-example" items={items} columns={columns} sortable getRowId={(item) => item.file.label} selectionMode="multiselect" resizableColumns resizableColumnsOptions={{ autoFitColumns: false }} columnSizingOptions={columnSizing} onColumnResize={onColumnResize}>
          <DataGridHeader>
            <DataGridRow selectionCell={{ checkboxIndicator: { 'aria-label': 'Select all rows' } }}>
              {({ renderHeaderCell, columnId }, dataGrid) => (<Menu openOnContext>
                  <MenuTrigger>
                    <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>
                  </MenuTrigger>
                  <MenuPopover>
                    <MenuList>
                      <MenuItem onClick={dataGrid.columnSizing_unstable.enableKeyboardMode(columnId)}>
                        Keyboard Column Resizing
                      </MenuItem>
                    </MenuList>
                  </MenuPopover>
                </Menu>)}
            </DataGridRow>
          </DataGridHeader>
          <DataGridBody<Item>>
            {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{ checkboxIndicator: { 'aria-label': 'Select row' } }}>
                {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
              </DataGridRow>)}
          </DataGridBody>
        </DataGrid>
      </>);
};

export default ResizableColumnsControlled;

Resizable Columns - Disabled container auto-fit

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { DataGrid } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { Menu } from "@coreai-ds/react-components";
import { MenuTrigger } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { MenuPopover } from "@coreai-ds/react-components";
import { MenuList } from "@coreai-ds/react-components";
import { MenuItem } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type LastUpdateCell = {
    label: string;
    icon: JSXElement;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
    lastUpdate: LastUpdateCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
        lastUpdate: {
            label: 'You edited this',
            icon: <EditRegular />,
        },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
        lastUpdate: {
            label: 'You shared this in a Teams chat',
            icon: <PeopleRegular />,
        },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        compare: (a, b) => {
            return a.file.label.localeCompare(b.file.label);
        },
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return (<TableCellLayout truncate media={item.file.icon}>
          {item.file.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        compare: (a, b) => {
            return a.author.label.localeCompare(b.author.label);
        },
        renderHeaderCell: () => {
            return 'Author';
        },
        renderCell: item => {
            return (<TableCellLayout truncate media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdated',
        compare: (a, b) => {
            return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
        },
        renderHeaderCell: () => {
            return 'Last updated';
        },
        renderCell: item => {
            return <TableCellLayout truncate>{item.lastUpdated.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdate',
        compare: (a, b) => {
            return a.lastUpdate.label.localeCompare(b.lastUpdate.label);
        },
        renderHeaderCell: () => {
            return 'Last update';
        },
        renderCell: item => {
            return (<TableCellLayout truncate media={item.lastUpdate.icon}>
          {item.lastUpdate.label}
        </TableCellLayout>);
        },
    }),
];

const columnSizingOptions = {
    file: {
        minWidth: 80,
        defaultWidth: 180,
    },
    author: {
        defaultWidth: 180,
        minWidth: 120,
        idealWidth: 180,
    },
};

export const ResizableColumnsDisableAutoFit = (): JSXElement => {
    const refMap = React.useRef<Record<string, HTMLElement | null>>({});
    return (<div style={{ overflowX: 'auto' }}>
      <DataGrid items={items} columns={columns} sortable getRowId={item => item.file.label} selectionMode="multiselect" resizableColumns columnSizingOptions={columnSizingOptions} resizableColumnsOptions={{
            autoFitColumns: false,
        }}>
        <DataGridHeader>
          <DataGridRow selectionCell={{ checkboxIndicator: { 'aria-label': 'Select all rows' } }}>
            {({ renderHeaderCell, columnId }, dataGrid) => dataGrid.resizableColumns ? (<Menu openOnContext>
                  <MenuTrigger>
                    <DataGridHeaderCell ref={el => {
                refMap.current[columnId] = el;
            }}>
                      {renderHeaderCell()}
                    </DataGridHeaderCell>
                  </MenuTrigger>
                  <MenuPopover>
                    <MenuList>
                      <MenuItem onClick={dataGrid.columnSizing_unstable.enableKeyboardMode(columnId)}>
                        Keyboard Column Resizing
                      </MenuItem>
                    </MenuList>
                  </MenuPopover>
                </Menu>) : (<DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>)}
          </DataGridRow>
        </DataGridHeader>
        <DataGridBody<Item>>
          {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{ checkboxIndicator: { 'aria-label': 'Select row' } }}>
              {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
            </DataGridRow>)}
        </DataGridBody>
      </DataGrid>
    </div>);
};

export default ResizableColumnsDisableAutoFit;

Selection Appearance

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { DataGrid } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type LastUpdateCell = {
    label: string;
    icon: JSXElement;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
    lastUpdate: LastUpdateCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
        lastUpdate: {
            label: 'You edited this',
            icon: <EditRegular />,
        },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
        lastUpdate: {
            label: 'You shared this in a Teams chat',
            icon: <PeopleRegular />,
        },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        compare: (a, b) => {
            return a.file.label.localeCompare(b.file.label);
        },
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return <TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        compare: (a, b) => {
            return a.author.label.localeCompare(b.author.label);
        },
        renderHeaderCell: () => {
            return 'Author';
        },
        renderCell: item => {
            return (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdated',
        compare: (a, b) => {
            return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
        },
        renderHeaderCell: () => {
            return 'Last updated';
        },
        renderCell: item => {
            return item.lastUpdated.label;
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdate',
        compare: (a, b) => {
            return a.lastUpdate.label.localeCompare(b.lastUpdate.label);
        },
        renderHeaderCell: () => {
            return 'Last update';
        },
        renderCell: item => {
            return <TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>;
        },
    }),
];

export const SelectionAppearance = (): JSXElement => {
    const defaultSelectedItems = React.useMemo(() => new Set([1]), []);
    return (<DataGrid items={items} columns={columns} selectionMode="multiselect" selectionAppearance="neutral" defaultSelectedItems={defaultSelectedItems} style={{ minWidth: '550px' }}>
      <DataGridHeader>
        <DataGridRow selectionCell={{ checkboxIndicator: { 'aria-label': 'Select all rows' } }}>
          {({ renderHeaderCell }) => <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>}
        </DataGridRow>
      </DataGridHeader>
      <DataGridBody<Item>>
        {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{ checkboxIndicator: { 'aria-label': 'Select row' } }}>
            {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
          </DataGridRow>)}
      </DataGridBody>
    </DataGrid>);
};

export default SelectionAppearance;

Single Select

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { DataGrid } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type LastUpdateCell = {
    label: string;
    icon: JSXElement;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
    lastUpdate: LastUpdateCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
        lastUpdate: {
            label: 'You edited this',
            icon: <EditRegular />,
        },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
        lastUpdate: {
            label: 'You shared this in a Teams chat',
            icon: <PeopleRegular />,
        },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        compare: (a, b) => {
            return a.file.label.localeCompare(b.file.label);
        },
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return <TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        compare: (a, b) => {
            return a.author.label.localeCompare(b.author.label);
        },
        renderHeaderCell: () => {
            return 'Author';
        },
        renderCell: item => {
            return (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdated',
        compare: (a, b) => {
            return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
        },
        renderHeaderCell: () => {
            return 'Last updated';
        },
        renderCell: item => {
            return item.lastUpdated.label;
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdate',
        compare: (a, b) => {
            return a.lastUpdate.label.localeCompare(b.lastUpdate.label);
        },
        renderHeaderCell: () => {
            return 'Last update';
        },
        renderCell: item => {
            return <TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>;
        },
    }),
];

export const SingleSelect = (): JSXElement => {
    const defaultSelectedItems = React.useMemo(() => new Set([1]), []);
    return (<DataGrid items={items} columns={columns} selectionMode="single" defaultSelectedItems={defaultSelectedItems} style={{ minWidth: '550px' }}>
      <DataGridHeader>
        <DataGridRow>
          {({ renderHeaderCell }) => <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>}
        </DataGridRow>
      </DataGridHeader>
      <DataGridBody<Item>>
        {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{ radioIndicator: { 'aria-label': 'Select row' } }}>
            {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
          </DataGridRow>)}
      </DataGridBody>
    </DataGrid>);
};

export default SingleSelect;

Single Select Controlled

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import type { TableRowId } from "@coreai-ds/react-components";
import type { DataGridProps } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type LastUpdateCell = {
    label: string;
    icon: JSXElement;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
    lastUpdate: LastUpdateCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
        lastUpdate: {
            label: 'You edited this',
            icon: <EditRegular />,
        },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
        lastUpdate: {
            label: 'You shared this in a Teams chat',
            icon: <PeopleRegular />,
        },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        compare: (a, b) => {
            return a.file.label.localeCompare(b.file.label);
        },
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return <TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        compare: (a, b) => {
            return a.author.label.localeCompare(b.author.label);
        },
        renderHeaderCell: () => {
            return 'Author';
        },
        renderCell: item => {
            return (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdated',
        compare: (a, b) => {
            return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
        },
        renderHeaderCell: () => {
            return 'Last updated';
        },
        renderCell: item => {
            return item.lastUpdated.label;
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdate',
        compare: (a, b) => {
            return a.lastUpdate.label.localeCompare(b.lastUpdate.label);
        },
        renderHeaderCell: () => {
            return 'Last update';
        },
        renderCell: item => {
            return <TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>;
        },
    }),
];

export const SingleSelectControlled = (): JSXElement => {
    const [selectedRows, setSelectedRows] = React.useState(new Set<TableRowId>([1]));
    const onSelectionChange: DataGridProps['onSelectionChange'] = (e, data) => {
        setSelectedRows(data.selectedItems);
    };
    return (<DataGrid items={items} columns={columns} selectionMode="single" selectedItems={selectedRows} onSelectionChange={onSelectionChange} style={{ minWidth: '550px' }}>
      <DataGridHeader>
        <DataGridRow>
          {({ renderHeaderCell }) => <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>}
        </DataGridRow>
      </DataGridHeader>
      <DataGridBody<Item>>
        {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{ radioIndicator: { 'aria-label': 'Select row' } }}>
            {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
          </DataGridRow>)}
      </DataGridBody>
    </DataGrid>);
};

export default SingleSelectControlled;

Sort

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import type { DataGridProps } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type LastUpdateCell = {
    label: string;
    icon: JSXElement;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
    lastUpdate: LastUpdateCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
        lastUpdate: {
            label: 'You edited this',
            icon: <EditRegular />,
        },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
        lastUpdate: {
            label: 'You shared this in a Teams chat',
            icon: <PeopleRegular />,
        },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        compare: (a, b) => {
            return a.file.label.localeCompare(b.file.label);
        },
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return <TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        compare: (a, b) => {
            return a.author.label.localeCompare(b.author.label);
        },
        renderHeaderCell: () => {
            return 'Author';
        },
        renderCell: item => {
            return (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdated',
        compare: (a, b) => {
            return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
        },
        renderHeaderCell: () => {
            return 'Last updated';
        },
        renderCell: item => {
            return item.lastUpdated.label;
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdate',
        renderHeaderCell: () => {
            return 'Not sortable';
        },
        renderCell: item => {
            return <TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>;
        },
    }),
];

export const Sort = (): JSXElement => {
    const defaultSortState = React.useMemo<Parameters<NonNullable<DataGridProps['onSortChange']>>[1]>(() => ({ sortColumn: 'file', sortDirection: 'ascending' }), []);
    return (<DataGrid items={items} columns={columns} sortable defaultSortState={defaultSortState} style={{ minWidth: '500px' }}>
      <DataGridHeader>
        <DataGridRow>
          {({ renderHeaderCell }) => <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>}
        </DataGridRow>
      </DataGridHeader>
      <DataGridBody<Item>>
        {({ item, rowId }) => (<DataGridRow<Item> key={rowId}>
            {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
          </DataGridRow>)}
      </DataGridBody>
    </DataGrid>);
};

export default Sort;

Sort Controlled

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import type { DataGridProps } from "@coreai-ds/react-components";
import { DataGrid } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type LastUpdateCell = {
    label: string;
    icon: JSXElement;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
    lastUpdate: LastUpdateCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
        lastUpdate: {
            label: 'You edited this',
            icon: <EditRegular />,
        },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
        lastUpdate: {
            label: 'You shared this in a Teams chat',
            icon: <PeopleRegular />,
        },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        compare: (a, b) => {
            return a.file.label.localeCompare(b.file.label);
        },
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return <TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        compare: (a, b) => {
            return a.author.label.localeCompare(b.author.label);
        },
        renderHeaderCell: () => {
            return 'Author';
        },
        renderCell: item => {
            return (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdated',
        compare: (a, b) => {
            return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
        },
        renderHeaderCell: () => {
            return 'Last updated';
        },
        renderCell: item => {
            return item.lastUpdated.label;
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdate',
        compare: (a, b) => {
            return a.lastUpdate.label.localeCompare(b.lastUpdate.label);
        },
        renderHeaderCell: () => {
            return 'Last update';
        },
        renderCell: item => {
            return <TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>;
        },
    }),
];

export const SortControlled = (): JSXElement => {
    const [sortState, setSortState] = React.useState<Parameters<NonNullable<DataGridProps['onSortChange']>>[1]>({
        sortColumn: 'file',
        sortDirection: 'ascending',
    });
    const onSortChange: DataGridProps['onSortChange'] = (e, nextSortState) => {
        setSortState(nextSortState);
    };
    return (<DataGrid items={items} columns={columns} sortable sortState={sortState} onSortChange={onSortChange} style={{ minWidth: '500px' }}>
      <DataGridHeader>
        <DataGridRow>
          {({ renderHeaderCell }) => <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>}
        </DataGridRow>
      </DataGridHeader>
      <DataGridBody<Item>>
        {({ item, rowId }) => (<DataGridRow<Item> key={rowId}>
            {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
          </DataGridRow>)}
      </DataGridBody>
    </DataGrid>);
};

export default SortControlled;

Subtle Selection

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { DataGrid } from "@coreai-ds/react-components";
import type { PresenceBadgeStatus } from "@coreai-ds/react-components";
import { DocumentRegular } from "@fluentui/react-icons";
import { EditRegular } from "@fluentui/react-icons";
import { FolderRegular } from "@fluentui/react-icons";
import { OpenRegular } from "@fluentui/react-icons";
import { VideoRegular } from "@fluentui/react-icons";
import { DocumentPdfRegular } from "@fluentui/react-icons";
import { PeopleRegular } from "@fluentui/react-icons";
import type { TableColumnDefinition } from "@coreai-ds/react-components";
import { createTableColumn } from "@coreai-ds/react-components";
import { TableCellLayout } from "@coreai-ds/react-components";
import { Avatar } from "@coreai-ds/react-components";
import { DataGridHeader } from "@coreai-ds/react-components";
import { DataGridRow } from "@coreai-ds/react-components";
import { DataGridHeaderCell } from "@coreai-ds/react-components";
import { DataGridBody } from "@coreai-ds/react-components";
import { DataGridCell } from "@coreai-ds/react-components";

type FileCell = {
    label: string;
    icon: JSXElement;
};

type AuthorCell = {
    label: string;
    status: PresenceBadgeStatus;
};

type LastUpdatedCell = {
    label: string;
    timestamp: number;
};

type LastUpdateCell = {
    label: string;
    icon: JSXElement;
};

type Item = {
    file: FileCell;
    author: AuthorCell;
    lastUpdated: LastUpdatedCell;
    lastUpdate: LastUpdateCell;
};

const items: Item[] = [
    {
        file: { label: 'Meeting notes', icon: <DocumentRegular /> },
        author: { label: 'Max Mustermann', status: 'available' },
        lastUpdated: { label: '7h ago', timestamp: 1 },
        lastUpdate: {
            label: 'You edited this',
            icon: <EditRegular />,
        },
    },
    {
        file: { label: 'Thursday presentation', icon: <FolderRegular /> },
        author: { label: 'Erika Mustermann', status: 'busy' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Training recording', icon: <VideoRegular /> },
        author: { label: 'John Doe', status: 'away' },
        lastUpdated: { label: 'Yesterday at 1:45 PM', timestamp: 2 },
        lastUpdate: {
            label: 'You recently opened this',
            icon: <OpenRegular />,
        },
    },
    {
        file: { label: 'Purchase order', icon: <DocumentPdfRegular /> },
        author: { label: 'Jane Doe', status: 'offline' },
        lastUpdated: { label: 'Tue at 9:30 AM', timestamp: 3 },
        lastUpdate: {
            label: 'You shared this in a Teams chat',
            icon: <PeopleRegular />,
        },
    },
];

const columns: TableColumnDefinition<Item>[] = [
    createTableColumn<Item>({
        columnId: 'file',
        compare: (a, b) => {
            return a.file.label.localeCompare(b.file.label);
        },
        renderHeaderCell: () => {
            return 'File';
        },
        renderCell: item => {
            return <TableCellLayout media={item.file.icon}>{item.file.label}</TableCellLayout>;
        },
    }),
    createTableColumn<Item>({
        columnId: 'author',
        compare: (a, b) => {
            return a.author.label.localeCompare(b.author.label);
        },
        renderHeaderCell: () => {
            return 'Author';
        },
        renderCell: item => {
            return (<TableCellLayout media={<Avatar aria-label={item.author.label} name={item.author.label} badge={{ status: item.author.status }}/>}>
          {item.author.label}
        </TableCellLayout>);
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdated',
        compare: (a, b) => {
            return a.lastUpdated.timestamp - b.lastUpdated.timestamp;
        },
        renderHeaderCell: () => {
            return 'Last updated';
        },
        renderCell: item => {
            return item.lastUpdated.label;
        },
    }),
    createTableColumn<Item>({
        columnId: 'lastUpdate',
        compare: (a, b) => {
            return a.lastUpdate.label.localeCompare(b.lastUpdate.label);
        },
        renderHeaderCell: () => {
            return 'Last update';
        },
        renderCell: item => {
            return <TableCellLayout media={item.lastUpdate.icon}>{item.lastUpdate.label}</TableCellLayout>;
        },
    }),
];

export const SubtleSelection = (): JSXElement => {
    const defaultSelectedItems = React.useMemo(() => new Set([1]), []);
    return (<DataGrid items={items} columns={columns} selectionMode="multiselect" subtleSelection defaultSelectedItems={defaultSelectedItems} style={{ minWidth: '550px' }}>
      <DataGridHeader>
        <DataGridRow selectionCell={{ checkboxIndicator: { 'aria-label': 'Select all rows' } }}>
          {({ renderHeaderCell }) => <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>}
        </DataGridRow>
      </DataGridHeader>
      <DataGridBody<Item>>
        {({ item, rowId }) => (<DataGridRow<Item> key={rowId} selectionCell={{ checkboxIndicator: { 'aria-label': 'Select row' } }}>
            {({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
          </DataGridRow>)}
      </DataGridBody>
    </DataGrid>);
};

export default SubtleSelection;

Virtualization

Loading interactive example. Full source is available below.

Download source
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';

export const Virtualization = (): JSXElement => {
    return (<iframe style={{ width: '100%', height: 500, border: 'none' }} src="https://microsoft.github.io/fluentui-contrib/react-data-grid-react-window/iframe.html?id=packages-react-data-grid-react-window--virtualized-data-grid&viewMode=story"/>);
};

export default Virtualization;