Comprehensive React component library implementing Microsoft's Fluent Design System for building Office 365 experiences
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
High-performance components for displaying structured data including virtualized lists, data tables, and user representation elements optimized for large datasets and responsive layouts.
High-performance data table component with sorting, filtering, selection, and virtualization support for displaying large datasets.
/**
* High-performance data table with virtualization and selection support
*/
function DetailsList(props: IDetailsListProps): JSX.Element;
interface IDetailsList {
/** Force update of the list */
forceUpdate(): void;
/** Focus on a specific item by index */
focusIndex(index: number): void;
}
interface IDetailsListProps {
/** Reference to access component methods */
componentRef?: IRefObject<IDetailsList>;
/** Array of data items to display */
items: any[];
/** Column definitions for the table */
columns: IColumn[];
/** Group definitions for hierarchical data */
groups?: IGroup[];
/** Properties for group rendering */
groupProps?: IDetailsGroupRenderProps;
/** Selection manager instance */
selection?: ISelection;
/** Selection mode (none, single, multiple) */
selectionMode?: SelectionMode;
/** Layout mode for columns */
layoutMode?: DetailsListLayoutMode;
/** Whether to use compact row spacing */
compact?: boolean;
/** Whether the header is visible */
isHeaderVisible?: boolean;
/** Whether virtualization is enabled */
enableShimmer?: boolean;
/** Shimmer lines count */
shimmerLines?: number;
/** Checkbox visibility mode */
checkboxVisibility?: CheckboxVisibility;
/** Constraint mode for column sizing */
constrainMode?: ConstrainMode;
/** Unique key for force re-render */
setKey?: string;
/** Initial focused index */
initialFocusedIndex?: number;
/** Whether to disable selection on click */
disableSelectionZone?: boolean;
/** Whether to preserve selection on empty click */
selectionPreservedOnEmptyClick?: boolean;
/** Aria label for the list */
ariaLabel?: string;
/** Aria labelledby for the list */
ariaLabelledBy?: string;
/** Role for the list */
role?: string;
/** Row element type */
rowElementEventMap?: { [eventName: string]: (context: IDetailsRowProps, ev?: any) => void };
/** Whether to use reduced row renderer */
useReducedRowRenderer?: boolean;
/** Custom render function for missing items */
onRenderMissingItem?: (index?: number, rowProps?: IDetailsRowProps) => React.ReactNode;
/** Custom render function for item column */
onRenderItemColumn?: (item?: any, index?: number, column?: IColumn) => React.ReactNode;
/** Custom render function for row */
onRenderRow?: IDetailsListProps["onRenderRow"];
/** Custom render function for details header */
onRenderDetailsHeader?: IRenderFunction<IDetailsHeaderProps>;
/** Custom render function for details footer */
onRenderDetailsFooter?: IRenderFunction<IDetailsFooterProps>;
/** Callback fired when item is invoked (double-click or enter) */
onItemInvoked?: (item?: any, index?: number, ev?: Event) => void;
/** Callback fired when item context menu is invoked */
onItemContextMenu?: (item?: any, index?: number, ev?: Event) => void | boolean;
/** Callback fired when column header is clicked */
onColumnHeaderClick?: (ev?: React.MouseEvent<HTMLElement>, column?: IColumn) => void;
/** Callback fired when column header context menu is invoked */
onColumnHeaderContextMenu?: (column?: IColumn, ev?: React.MouseEvent<HTMLElement>) => void;
/** Callback fired when should update focus */
onShouldVirtualize?: (props: IListProps) => boolean;
/** Callback fired when active item changes */
onActiveItemChanged?: (item?: any, index?: number, ev?: React.FocusEvent<HTMLElement>) => void;
/** Callback fired when column resize starts */
onColumnResize?: (column?: IColumn, newWidth?: number, columnIndex?: number) => void;
/** Custom styles */
styles?: IStyleFunctionOrObject<IDetailsListStyleProps, IDetailsListStyles>;
/** Theme provided by higher-order component */
theme?: ITheme;
/** Additional CSS class */
className?: string;
/** List properties for virtualization */
listProps?: IListProps;
/** Group properties */
groupProps?: IDetailsGroupRenderProps;
/** Drag drop helper for reordering */
dragDropEvents?: IDragDropEvents;
/** Viewport for virtualization */
viewport?: IViewport;
/** Minimum rows to render */
minimumPixelsForDrag?: number;
/** Compact mode */
compact?: boolean;
}
interface IColumn {
/** Unique key for the column */
key: string;
/** Display name for the column header */
name: string;
/** Field name in the data item */
fieldName?: string;
/** Minimum width in pixels */
minWidth: number;
/** Maximum width in pixels */
maxWidth?: number;
/** Current width in pixels */
currentWidth?: number;
/** Whether the column is resizable */
isResizable?: boolean;
/** Whether the column is sortable */
isSorted?: boolean;
/** Whether the column is sorted descending */
isSortedDescending?: boolean;
/** Whether the column is filtered */
isFiltered?: boolean;
/** Whether this column serves as row header */
isRowHeader?: boolean;
/** Whether the column content can wrap */
isMultiline?: boolean;
/** Whether the column is grouped */
isGrouped?: boolean;
/** Whether the column has padding */
isPadded?: boolean;
/** Icon name for the column header */
iconName?: string;
/** Icon class name for the column header */
iconClassName?: string;
/** Column actions mode */
columnActionsMode?: ColumnActionsMode;
/** Header class name */
headerClassName?: string;
/** Custom render function for column header */
onRenderHeader?: IRenderFunction<IDetailsColumnProps>;
/** Custom render function for column content */
onRender?: (item?: any, index?: number, column?: IColumn) => React.ReactNode;
/** Callback fired when column header is clicked */
onColumnClick?: (ev: React.MouseEvent<HTMLElement>, column: IColumn) => void;
/** Callback fired when column header context menu is invoked */
onColumnContextMenu?: (column?: IColumn, ev?: React.MouseEvent<HTMLElement>) => void;
/** Callback fired when column is resized */
onColumnResize?: (width?: number) => void;
/** Filter aria label */
filterAriaLabel?: string;
/** Sort aria label */
sortAscendingAriaLabel?: string;
/** Sort aria label for descending */
sortDescendingAriaLabel?: string;
/** Group aria label */
groupAriaLabel?: string;
/** Aria label for the column */
ariaLabel?: string;
/** Additional data for the column */
data?: any;
/** Calculated width */
calculatedWidth?: number;
}
enum DetailsListLayoutMode {
fixedColumns = 0,
justified = 1
}
enum ColumnActionsMode {
disabled = 0,
clickable = 1,
hasDropdown = 2
}
enum ConstrainMode {
unconstrained = 0,
horizontalConstrained = 1
}
enum CheckboxVisibility {
onHover = 0,
always = 1,
hidden = 2
}
enum SelectionMode {
none = 0,
single = 1,
multiple = 2
}Usage Examples:
import React, { useState, useMemo } from "react";
import {
DetailsList,
IColumn,
DetailsListLayoutMode,
SelectionMode,
Selection
} from "office-ui-fabric-react";
interface IItem {
key: string;
name: string;
email: string;
department: string;
status: string;
lastActive: Date;
}
function BasicDetailsList() {
const items: IItem[] = [
{
key: "1",
name: "John Doe",
email: "john@example.com",
department: "Engineering",
status: "Active",
lastActive: new Date("2023-12-01")
},
{
key: "2",
name: "Jane Smith",
email: "jane@example.com",
department: "Design",
status: "Away",
lastActive: new Date("2023-11-28")
},
{
key: "3",
name: "Bob Johnson",
email: "bob@example.com",
department: "Marketing",
status: "Active",
lastActive: new Date("2023-12-02")
}
];
const columns: IColumn[] = [
{
key: "name",
name: "Name",
fieldName: "name",
minWidth: 150,
maxWidth: 300,
isResizable: true,
isRowHeader: true,
isSorted: true,
isSortedDescending: false,
onColumnClick: (ev, column) => {
console.log("Sort by name", column);
}
},
{
key: "email",
name: "Email",
fieldName: "email",
minWidth: 200,
maxWidth: 400,
isResizable: true,
onRender: (item: IItem) => {
return <a href={`mailto:${item.email}`}>{item.email}</a>;
}
},
{
key: "department",
name: "Department",
fieldName: "department",
minWidth: 120,
maxWidth: 200,
isResizable: true
},
{
key: "status",
name: "Status",
fieldName: "status",
minWidth: 80,
maxWidth: 120,
onRender: (item: IItem) => {
const statusColor = item.status === "Active" ? "#107C10" : "#FF8C00";
return (
<span style={{ color: statusColor, fontWeight: 600 }}>
{item.status}
</span>
);
}
},
{
key: "lastActive",
name: "Last Active",
fieldName: "lastActive",
minWidth: 120,
maxWidth: 180,
onRender: (item: IItem) => {
return item.lastActive.toLocaleDateString();
}
}
];
return (
<DetailsList
items={items}
columns={columns}
setKey="set"
layoutMode={DetailsListLayoutMode.justified}
selectionMode={SelectionMode.multiple}
onItemInvoked={(item) => console.log("Item invoked:", item)}
ariaLabel="Employee list"
/>
);
}
function SelectableDetailsList() {
const [items] = useState<IItem[]>([
// ... same items as above
]);
const [selectedItems, setSelectedItems] = useState<IItem[]>([]);
const selection: Selection = useMemo(() => {
return new Selection({
onSelectionChanged: () => {
setSelectedItems(selection.getSelection() as IItem[]);
}
});
}, []);
const columns: IColumn[] = [
// ... same columns as above
];
return (
<div>
<div style={{ marginBottom: 10 }}>
Selected items: {selectedItems.length}
</div>
<DetailsList
items={items}
columns={columns}
setKey="set"
layoutMode={DetailsListLayoutMode.justified}
selection={selection}
selectionPreservedOnEmptyClick
ariaLabel="Selectable employee list"
/>
</div>
);
}Virtualized list component optimized for displaying large datasets with efficient rendering and scrolling.
/**
* Virtualized list component for large datasets
*/
function List<T>(props: IListProps<T>): JSX.Element;
interface IList {
/** Force update of the list */
forceUpdate(): void;
/** Scroll to a specific index */
scrollToIndex(index: number, measureItem?: (itemIndex: number) => number, scrollToMode?: ScrollToMode): void;
/** Focus on a specific index */
focusIndex(index: number, forceIntoFirstElement?: boolean, measureItem?: (itemIndex: number) => number): void;
/** Get the current scroll position */
getStartItemIndexInView(measureItem?: (itemIndex: number) => number): number;
}
interface IListProps<T = any> {
/** Reference to access component methods */
componentRef?: IRefObject<IList>;
/** Array of items to render */
items?: T[];
/** Function to render each item */
onRenderCell: (item?: T, index?: number, isScrolling?: boolean) => React.ReactNode;
/** Function to get a unique key for each item */
getKey?: (item: T, index?: number) => string;
/** Initial focused index */
initialFocusedIndex?: number;
/** Class name for the list */
className?: string;
/** Role for accessibility */
role?: string;
/** Whether the list should start updates */
startIndex?: number;
/** Whether to render all items (disable virtualization) */
renderCount?: number;
/** Item height in pixels (for fixed height items) */
getItemCountForPage?: (visibleRect?: IRectangle, allItems?: T[]) => number;
/** Function to get page height */
getPageHeight?: (visibleRect?: IRectangle, allItems?: T[], itemIndex?: number) => number;
/** Page key for render optimization */
usePageCache?: boolean;
/** Custom render function for page */
onRenderPage?: (pageProps: IPageProps, defaultRender?: IRenderFunction<IPageProps>) => React.ReactNode;
/** Function to measure item height dynamically */
getPageSpecification?: (itemIndex?: number, visibleRect?: IRectangle) => IPageSpecification;
/** Callback fired when the rendered range changes */
onPagesUpdated?: (pages: IPage[]) => void;
/** Callback fired when items are rendered */
onShouldVirtualize?: (props: IListProps) => boolean;
/** Custom styles */
styles?: IStyleFunctionOrObject<IListStyleProps, IListStyles>;
/** Theme provided by higher-order component */
theme?: ITheme;
/** Version for cache invalidation */
version?: {};
/** Items per page */
renderedWindowsAhead?: number;
/** Items per page behind */
renderedWindowsBehind?: number;
/** Ignore scroll events */
ignoreScrollingState?: boolean;
}
enum ScrollToMode {
auto = 0,
top = 1,
bottom = 2,
center = 3
}Hierarchical list component with expandable groups for organizing related data items.
/**
* Hierarchical list with expandable groups
*/
function GroupedList(props: IGroupedListProps): JSX.Element;
interface IGroupedList {
/** Force update of the list */
forceUpdate(): void;
/** Toggle group expansion */
toggleCollapseAll(allCollapsed: boolean): void;
}
interface IGroupedListProps {
/** Reference to access component methods */
componentRef?: IRefObject<IGroupedList>;
/** Array of items to display */
items: any[];
/** Function to render each item */
onRenderCell: (nestingDepth?: number, item?: any, itemIndex?: number) => React.ReactNode;
/** Selection manager */
selection?: ISelection;
/** Selection mode */
selectionMode?: SelectionMode;
/** Group definitions */
groups?: IGroup[];
/** Whether to show empty groups */
showEmptyGroups?: boolean;
/** Compact mode */
compact?: boolean;
/** Properties for drag and drop */
dragDropEvents?: IDragDropEvents;
/** Properties for group headers */
groupProps?: IGroupRenderProps;
/** Custom render function for group header */
onRenderGroupHeader?: (props?: IGroupDividerProps) => React.ReactNode;
/** Custom render function for group footer */
onRenderGroupFooter?: (props?: IGroupDividerProps) => React.ReactNode;
/** Function to get group key */
getGroupKey?: (group: IGroup, index: number) => string;
/** Callback fired when group header is clicked */
onGroupHeaderClick?: (group?: IGroup) => void;
/** Callback fired when group expand state changes */
onGroupExpandStateChanged?: (isSomeGroupExpanded?: boolean) => void;
/** Custom styles */
styles?: IStyleFunctionOrObject<IGroupedListStyleProps, IGroupedListStyles>;
/** Theme provided by higher-order component */
theme?: ITheme;
/** Additional CSS class */
className?: string;
/** List properties */
listProps?: IListProps;
/** Use page cache */
usePageCache?: boolean;
/** Callback fired when should virtualize */
onShouldVirtualize?: (props: IListProps) => boolean;
}
interface IGroup {
/** Unique key for the group */
key: string;
/** Display name for the group */
name: string;
/** Start index in the items array */
startIndex: number;
/** Number of items in the group */
count: number;
/** Nesting level */
level?: number;
/** Whether the group is collapsed */
isCollapsed?: boolean;
/** Whether the group shows all items */
isShowingAll?: boolean;
/** Whether drag and drop is enabled */
isDropEnabled?: boolean;
/** Additional data */
data?: any;
/** Child groups */
children?: IGroup[];
/** Whether there are more items to load */
hasMoreData?: boolean;
/** Color for the group */
color?: string;
}User representation component with avatar and details for displaying user information.
/**
* User representation component with avatar and details
*/
function Persona(props: IPersonaProps): JSX.Element;
interface IPersona {
/** Current persona size */
persona: IPersonaProps;
}
interface IPersonaProps {
/** Reference to access component methods */
componentRef?: IRefObject<IPersona>;
/** Primary text (usually the name) */
text?: string;
/** Secondary text (usually title or department) */
secondaryText?: string;
/** Tertiary text (additional info) */
tertiaryText?: string;
/** Optional text (status or location) */
optionalText?: string;
/** URL or data URL for the avatar image */
imageUrl?: string;
/** Alt text for the avatar image */
imageAlt?: string;
/** Initials to display if no image */
imageInitials?: string;
/** Whether the image should cover the entire area */
imageShouldFadeIn?: boolean;
/** Whether the image should start visible */
imageShouldStartVisible?: boolean;
/** Persona size */
size?: PersonaSize;
/** Persona presence (online status) */
presence?: PersonaPresence;
/** Presence title */
presenceTitle?: string;
/** Colors for the presence indicator */
presenceColors?: IPersonaPresenceColors;
/** Coin properties for the avatar */
coinProps?: IPersonaCoinProps;
/** Show unknown persona coin */
showUnknownPersonaCoin?: boolean;
/** Whether to show the secondary text on a new line */
showSecondaryText?: boolean;
/** Whether to show the initials color */
showInitialsUntilImageLoads?: boolean;
/** Whether to hide the persona details */
hidePersonaDetails?: boolean;
/** Custom render function for the coin */
onRenderCoin?: IRenderFunction<IPersonaCoinProps>;
/** Custom render function for primary text */
onRenderPrimaryText?: IRenderFunction<IPersonaProps>;
/** Custom render function for secondary text */
onRenderSecondaryText?: IRenderFunction<IPersonaProps>;
/** Custom render function for tertiary text */
onRenderTertiaryText?: IRenderFunction<IPersonaProps>;
/** Custom render function for optional text */
onRenderOptionalText?: IRenderFunction<IPersonaProps>;
/** Allow phone number clicks */
allowPhoneInitials?: boolean;
/** Click handler for the persona */
onClick?: (ev?: React.MouseEvent<HTMLElement>) => void;
/** Context menu handler */
onMouseMove?: (ev?: React.MouseEvent<HTMLElement>) => void;
/** Custom styles */
styles?: IStyleFunctionOrObject<IPersonaStyleProps, IPersonaStyles>;
/** Theme provided by higher-order component */
theme?: ITheme;
/** Additional CSS class */
className?: string;
}
enum PersonaSize {
size8 = 0,
size10 = 1,
tiny = 1,
size16 = 2,
size24 = 3,
size28 = 4,
size32 = 5,
size40 = 6,
size48 = 7,
size56 = 8,
size72 = 9,
size100 = 10,
size120 = 11
}
enum PersonaPresence {
none = 0,
offline = 1,
online = 2,
away = 3,
dnd = 4,
blocked = 5,
busy = 6
}Standalone avatar component showing just the circular user image or initials portion of a Persona.
/**
* Standalone circular avatar component
*/
function PersonaCoin(props: IPersonaCoinProps): JSX.Element;
interface IPersonaCoin {
/** Current persona coin props */
persona: IPersonaCoinProps;
}
interface IPersonaCoinProps {
/** Reference to access component methods */
componentRef?: IRefObject<IPersonaCoin>;
/** Primary text for generating initials */
text?: string;
/** URL or data URL for the avatar image */
imageUrl?: string;
/** Alt text for the avatar image */
imageAlt?: string;
/** Custom initials override */
imageInitials?: string;
/** Whether the image should fade in */
imageShouldFadeIn?: boolean;
/** Whether the image should start visible */
imageShouldStartVisible?: boolean;
/** Size of the persona coin */
size?: PersonaSize;
/** Presence indicator */
presence?: PersonaPresence;
/** Title for the presence indicator */
presenceTitle?: string;
/** Colors for the presence indicator */
presenceColors?: IPersonaPresenceColors;
/** Whether to show unknown persona coin */
showUnknownPersonaCoin?: boolean;
/** Whether to show initials while image loads */
showInitialsUntilImageLoads?: boolean;
/** Custom render function for initials */
onRenderInitials?: IRenderFunction<IPersonaCoinProps>;
/** Custom render function for the coin */
onRenderCoin?: IRenderFunction<IPersonaCoinProps>;
/** Custom render function for the presence */
onRenderPresence?: IRenderFunction<IPersonaCoinProps>;
/** Whether to allow phone number initials */
allowPhoneInitials?: boolean;
/** Click handler */
onClick?: (ev?: React.MouseEvent<HTMLElement>) => void;
/** Mouse move handler */
onMouseMove?: (ev?: React.MouseEvent<HTMLElement>) => void;
/** Custom styles */
styles?: IStyleFunctionOrObject<IPersonaCoinStyleProps, IPersonaCoinStyles>;
/** Theme provided by higher-order component */
theme?: ITheme;
/** Additional CSS class */
className?: string;
}Usage Examples:
import React from "react";
import {
Persona,
PersonaCoin,
PersonaSize,
PersonaPresence
} from "office-ui-fabric-react";
function BasicPersona() {
return (
<div>
<Persona
text="John Doe"
secondaryText="Software Engineer"
tertiaryText="Engineering Team"
optionalText="Available"
size={PersonaSize.size48}
presence={PersonaPresence.online}
imageUrl="https://example.com/avatar.jpg"
imageAlt="John Doe's avatar"
/>
<Persona
text="Jane Smith"
secondaryText="UX Designer"
size={PersonaSize.size40}
presence={PersonaPresence.away}
showSecondaryText
/>
</div>
);
}
function PersonaCoins() {
return (
<div style={{ display: "flex", gap: "10px", alignItems: "center" }}>
<PersonaCoin
text="Alice Johnson"
size={PersonaSize.size32}
presence={PersonaPresence.online}
/>
<PersonaCoin
text="Bob Wilson"
size={PersonaSize.size40}
presence={PersonaPresence.busy}
imageUrl="https://example.com/bob.jpg"
/>
<PersonaCoin
text="Carol Brown"
size={PersonaSize.size48}
presence={PersonaPresence.offline}
/>
</div>
);
}// Selection management interfaces
interface ISelection {
/** Number of selected items */
count: number;
/** Selection mode */
mode: SelectionMode;
/** Function to check if item can be selected */
canSelectItem: (item: any, index?: number) => boolean;
/** Get all items */
getItems(): any[];
/** Get selected item count */
getSelectedCount(): number;
/** Get selected item indices */
getSelectedIndices(): number[];
/** Get selected items */
getSelection(): any[];
/** Check if all items are selected */
isAllSelected(): boolean;
/** Check if specific item is selected by key */
isKeySelected(key: string): boolean;
/** Check if specific item is selected by index */
isIndexSelected(index: number): boolean;
/** Set all items selected state */
setAllSelected(isAllSelected: boolean): void;
/** Set items collection */
setItems(items: any[], shouldClear: boolean): void;
/** Set selection by key */
setKeySelected(key: string, isSelected: boolean, shouldAnchor: boolean): void;
/** Set selection by index */
setIndexSelected(index: number, isSelected: boolean, shouldAnchor: boolean): void;
/** Set range selection */
setRangeSelected(fromIndex: number, count: number, isSelected: boolean, shouldAnchor: boolean): void;
/** Toggle all items selection */
toggleAllSelected(): void;
/** Toggle selection by key */
toggleKeySelected(key: string): void;
/** Toggle selection by index */
toggleIndexSelected(index: number): void;
/** Toggle range selection */
toggleRangeSelected(fromIndex: number, count: number): void;
/** Set change events enabled state */
setChangeEvents(isEnabled: boolean, suppressChange?: boolean): void;
}
// Drag and drop interfaces
interface IDragDropEvents {
/** Whether drag and drop is enabled */
canDrag?: (item?: any, itemIndex?: number) => boolean;
/** Whether item can be dropped on target */
canDrop?: (dropContext?: IDragDropContext, dragContext?: IDragDropContext) => boolean;
/** Callback when drag starts */
onDragStart?: (item?: any, itemIndex?: number, selectedItems?: any[], event?: MouseEvent) => void;
/** Callback when dragging over target */
onDragEnter?: (item?: any, event?: DragEvent) => string;
/** Callback when drag leaves target */
onDragLeave?: (item?: any, event?: DragEvent) => void;
/** Callback when item is dropped */
onDrop?: (item?: any, event?: DragEvent) => void;
/** Callback when drag ends */
onDragEnd?: (item?: any, event?: DragEvent) => void;
}
interface IDragDropContext {
/** Data being dragged */
data: any;
/** Index of the item being dragged */
index: number;
/** Type of drag operation */
type: string;
}
// Virtualization interfaces
interface IViewport {
/** Width of the viewport */
width: number;
/** Height of the viewport */
height: number;
}
interface IRectangle {
/** Left position */
left: number;
/** Top position */
top: number;
/** Width */
width: number;
/** Height */
height: number;
/** Right edge (calculated) */
right?: number;
/** Bottom edge (calculated) */
bottom?: number;
}Install with Tessl CLI
npx tessl i tessl/npm-office-ui-fabric-react