Utility functions for DOM manipulation, focus management, performance optimization, and common operations. These utilities provide the foundation for Fluent UI React components and can be used independently.
Core utilities for DOM manipulation and browser detection.
/**
* Check if DOM is available (not server-side)
* @returns Whether DOM is available
*/
function canUseDOM(): boolean;
/**
* Get document reference safely
* @param element - Element to get document from
* @returns Document object or undefined
*/
function getDocument(element?: HTMLElement): Document | undefined;
/**
* Get window reference safely
* @param element - Element to get window from
* @returns Window object or undefined
*/
function getWindow(element?: HTMLElement): Window | undefined;
/**
* Get element bounding rectangle
* @param element - Element to measure
* @returns Rectangle object
*/
function getRect(element: HTMLElement): IRectangle;
/**
* Get scrollbar width for the current browser
* @returns Scrollbar width in pixels
*/
function getScrollbarWidth(): number;
/**
* Check if element contains another element
* @param parent - Parent element
* @param child - Child element
* @returns Whether parent contains child
*/
function elementContains(parent: HTMLElement, child: HTMLElement): boolean;
/**
* Check if element has specific attribute
* @param element - Element to check
* @param attribute - Attribute name
* @returns Whether element has attribute
*/
function elementContainsAttribute(element: HTMLElement, attribute: string): boolean;
/**
* Find scrollable parent element
* @param startingElement - Starting element
* @returns Scrollable parent or null
*/
function findScrollableParent(startingElement: HTMLElement): HTMLElement | null;
/**
* Check if element has horizontal overflow
* @param element - Element to check
* @returns Whether element has horizontal overflow
*/
function hasHorizontalOverflow(element: HTMLElement): boolean;
/**
* Check if element has vertical overflow
* @param element - Element to check
* @returns Whether element has vertical overflow
*/
function hasVerticalOverflow(element: HTMLElement): boolean;
/**
* Check if element has any overflow
* @param element - Element to check
* @returns Whether element has overflow
*/
function hasOverflow(element: HTMLElement): boolean;
/**
* Check if element is visible
* @param element - Element to check
* @returns Whether element is visible
*/
function isElementVisible(element: HTMLElement): boolean;
/**
* Check if element is tabbable
* @param element - Element to check
* @returns Whether element is tabbable
*/
function isElementTabbable(element: HTMLElement): boolean;
/**
* Allow scrolling on element
* @param element - Element to allow scrolling on
* @param events - Event group for cleanup
*/
function allowScrollOnElement(element: HTMLElement, events: EventGroup): void;
/**
* Disable body scrolling
*/
function disableBodyScroll(): void;
/**
* Enable body scrolling
*/
function enableBodyScroll(): void;
/**
* Check if browser is IE11
* @returns Whether browser is IE11
*/
function isIE11(): boolean;
/**
* Check if platform is iOS
* @returns Whether platform is iOS
*/
function isIOS(): boolean;
/**
* Check if platform is Mac
* @returns Whether platform is Mac
*/
function isMac(): boolean;
interface IRectangle {
left: number;
top: number;
width: number;
height: number;
right?: number;
bottom?: number;
}Utilities for managing focus and keyboard navigation.
/**
* Focus element asynchronously
* @param element - Element to focus
* @param callback - Optional callback
* @returns Whether focus was successful
*/
function focusAsync(element: HTMLElement, callback?: () => void): boolean;
/**
* Focus first child element
* @param rootElement - Root element to search within
* @returns Whether focus was successful
*/
function focusFirstChild(rootElement: HTMLElement): boolean;
/**
* Get first focusable element
* @param rootElement - Root element to search within
* @param currentElement - Current element
* @param includeElementsInFocusZones - Include focus zone elements
* @returns First focusable element or null
*/
function getFirstFocusable(
rootElement: HTMLElement,
currentElement?: HTMLElement,
includeElementsInFocusZones?: boolean
): HTMLElement | null;
/**
* Get first tabbable element
* @param rootElement - Root element to search within
* @param currentElement - Current element
* @param includeElementsInFocusZones - Include focus zone elements
* @returns First tabbable element or null
*/
function getFirstTabbable(
rootElement: HTMLElement,
currentElement?: HTMLElement,
includeElementsInFocusZones?: boolean
): HTMLElement | null;
/**
* Get last focusable element
* @param rootElement - Root element to search within
* @param currentElement - Current element
* @param includeElementsInFocusZones - Include focus zone elements
* @returns Last focusable element or null
*/
function getLastFocusable(
rootElement: HTMLElement,
currentElement?: HTMLElement,
includeElementsInFocusZones?: boolean
): HTMLElement | null;
/**
* Get last tabbable element
* @param rootElement - Root element to search within
* @param currentElement - Current element
* @param includeElementsInFocusZones - Include focus zone elements
* @returns Last tabbable element or null
*/
function getLastTabbable(
rootElement: HTMLElement,
currentElement?: HTMLElement,
includeElementsInFocusZones?: boolean
): HTMLElement | null;
/**
* Get next focusable element
* @param rootElement - Root element to search within
* @param currentElement - Current element
* @param checkNode - Check node function
* @param suppressParentTraversal - Suppress parent traversal
* @returns Next focusable element or null
*/
function getNextElement(
rootElement: HTMLElement,
currentElement: HTMLElement,
checkNode?: (element: HTMLElement) => boolean,
suppressParentTraversal?: boolean
): HTMLElement | null;
/**
* Get previous focusable element
* @param rootElement - Root element to search within
* @param currentElement - Current element
* @param checkNode - Check node function
* @param suppressChildTraversal - Suppress child traversal
* @returns Previous focusable element or null
*/
function getPreviousElement(
rootElement: HTMLElement,
currentElement: HTMLElement,
checkNode?: (element: HTMLElement) => boolean,
suppressChildTraversal?: boolean
): HTMLElement | null;
/**
* Check if focus should wrap
* @param element - Element to check
* @param noWrapDataAttribute - No wrap data attribute
* @returns Whether focus should wrap
*/
function shouldWrapFocus(element: HTMLElement, noWrapDataAttribute: string): boolean;
/**
* Check if element contains focus
* @param element - Element to check
* @returns Whether element contains focus
*/
function doesElementContainFocus(element: HTMLElement): boolean;
/**
* Check if element is a focus zone
* @param element - Element to check
* @returns Whether element is focus zone
*/
function isElementFocusZone(element?: HTMLElement): boolean;
/**
* Check if element is a focus sub-zone
* @param element - Element to check
* @returns Whether element is focus sub-zone
*/
function isElementFocusSubZone(element?: HTMLElement): boolean;Utilities for managing selection state and operations.
/**
* Selection change event constant
*/
const SELECTION_CHANGE: string;
/**
* Selection manager class
*/
class Selection implements ISelection {
constructor(options?: ISelectionOptions);
/** Get number of selected items */
getSelectedCount(): number;
/** Get array of selected items */
getSelection(): any[];
/** Check if index is selected */
isIndexSelected(index: number): boolean;
/** Check if all items are selected */
isAllSelected(): boolean;
/** Set all selected state */
setAllSelected(isAllSelected: boolean): void;
/** Set index selected state */
setIndexSelected(index: number, isSelected: boolean, shouldAnchor?: boolean): void;
/** Select to index */
selectToIndex(index: number, clearSelection?: boolean): void;
/** Toggle index selected */
toggleIndexSelected(index: number): void;
/** Toggle all selected */
toggleAllSelected(): void;
/** Toggle range selected */
toggleRangeSelected(fromIndex: number, count: number): void;
}
interface ISelection {
canSelectItem?: (item: any, index?: number) => boolean;
getKey?: (item: any, index?: number) => string;
getSelectedCount(): number;
getSelection(): any[];
isIndexSelected(index: number): boolean;
isAllSelected(): boolean;
setAllSelected(isAllSelected: boolean): void;
setIndexSelected(index: number, isSelected: boolean, shouldAnchor?: boolean): void;
selectToIndex(index: number, clearSelection?: boolean): void;
toggleIndexSelected(index: number): void;
toggleAllSelected(): void;
toggleRangeSelected(fromIndex: number, count: number): void;
}
interface ISelectionOptions {
onSelectionChanged?: () => void;
getKey?: (item: any, index?: number) => string;
canSelectItem?: (item: any, index?: number) => boolean;
selectionMode?: SelectionMode;
}
enum SelectionDirection {
horizontal = 0,
vertical = 1,
}
enum SelectionMode {
none = 0,
single = 1,
multiple = 2,
}
/**
* Get all selected options from a dropdown
* @param options - Dropdown options
* @param selectedKeys - Selected keys
* @returns Array of selected options
*/
function getAllSelectedOptions(options: any[], selectedKeys: (string | number)[]): any[];Utilities for performance optimization including memoization and async operations.
/**
* Create memoization function
* @param fn - Function to memoize
* @param maxCacheSize - Maximum cache size
* @returns Memoized function
*/
function createMemoizer<T extends (...args: any[]) => any>(fn: T, maxCacheSize?: number): T;
/**
* Memoize function results
* @param fn - Function to memoize
* @param resolver - Key resolver function
* @returns Memoized function
*/
function memoize<T extends (...args: any[]) => any>(
fn: T,
resolver?: (...args: any[]) => string
): T;
/**
* Function memoization decorator
* @param target - Target object
* @param key - Property key
* @param descriptor - Property descriptor
* @returns Modified descriptor
*/
function memoizeFunction<T extends Function>(
target: any,
key: string | number | symbol,
descriptor: TypedPropertyDescriptor<T>
): TypedPropertyDescriptor<T> | void;
/**
* Reset all memoizations
*/
function resetMemoizations(): void;
/**
* Set memoization to use WeakMap
* @param weakMap - Whether to use WeakMap
*/
function setMemoizeWeakMap(weakMap?: boolean): void;
/**
* Async operation utilities
*/
class Async {
constructor(parent?: object, onError?: (e: any) => void);
/** Set timeout with cleanup */
setTimeout(callback: () => void, duration: number): number;
/** Set interval with cleanup */
setInterval(callback: () => void, duration: number): number;
/** Set immediate with cleanup */
setImmediate(callback: () => void): number;
/** Request animation frame with cleanup */
requestAnimationFrame(callback: () => void): number;
/** Throttle function calls */
throttle<T extends Function>(func: T, wait?: number, options?: { leading?: boolean; trailing?: boolean }): T;
/** Debounce function calls */
debounce<T extends Function>(func: T, wait?: number, options?: { leading?: boolean; trailing?: boolean }): T;
/** Dispose all async operations */
dispose(): void;
}
/**
* Safe request animation frame
* @param callback - Callback function
* @returns Request ID
*/
function safeRequestAnimationFrame(callback: () => void): number;
/**
* Safe set timeout
* @param callback - Callback function
* @param duration - Timeout duration
* @returns Timer ID
*/
function safeSetTimeout(callback: () => void, duration: number): number;
/**
* Performance measurement utilities
*/
class FabricPerformance {
/** Measure performance of function */
static measure(name: string, fn: () => void): void;
/** Get performance summary */
static getSummary(): IPerfSummary;
/** Reset performance measurements */
static reset(): void;
}
interface IPerfSummary {
[measureName: string]: IPerfMeasurement;
}
interface IPerfMeasurement {
totalDuration: number;
count: number;
average: number;
min: number;
max: number;
}Event management and keyboard utilities.
/**
* Event group for managing event listeners
*/
class EventGroup {
constructor(parent: any);
/** Add event listener */
on(
element: any,
eventName: string,
callback: (event?: any) => void,
options?: boolean | AddEventListenerOptions
): void;
/** Remove event listener */
off(
element?: any,
eventName?: string,
callback?: (event?: any) => void
): void;
/** Raise event */
raise(eventName: string, eventArgs?: any, bubbleEvent?: boolean): boolean | undefined;
/** Dispose all event listeners */
dispose(): void;
}
/**
* Keyboard key codes
*/
const KeyCodes: {
a: number;
b: number;
c: number;
d: number;
e: number;
f: number;
g: number;
h: number;
i: number;
j: number;
k: number;
l: number;
m: number;
n: number;
o: number;
p: number;
q: number;
r: number;
s: number;
t: number;
u: number;
v: number;
w: number;
x: number;
y: number;
z: number;
zero: number;
one: number;
two: number;
three: number;
four: number;
five: number;
six: number;
seven: number;
eight: number;
nine: number;
space: number;
enter: number;
tab: number;
escape: number;
backspace: number;
delete: number;
left: number;
up: number;
right: number;
down: number;
home: number;
end: number;
pageUp: number;
pageDown: number;
insert: number;
f1: number;
f2: number;
f3: number;
f4: number;
f5: number;
f6: number;
f7: number;
f8: number;
f9: number;
f10: number;
f11: number;
f12: number;
semicolon: number;
comma: number;
period: number;
dash: number;
slash: number;
graveAccent: number;
openBracket: number;
backSlash: number;
closeBracket: number;
singleQuote: number;
};
/**
* Check if key code is directional
* @param which - Key code
* @returns Whether key is directional
*/
function isDirectionalKeyCode(which: number): boolean;
/**
* Add directional key code
* @param which - Key code to add
*/
function addDirectionalKeyCode(which: number): void;
/**
* Remove directional key code
* @param which - Key code to remove
*/
function removeDirectionalKeyCode(which: number): void;
/**
* Get RTL-safe key code
* @param which - Key code
* @param isRTL - Whether RTL mode
* @returns RTL-safe key code
*/
function getRTLSafeKeyCode(which: number, isRTL?: boolean): number;Common utility functions for strings, objects, arrays, and IDs.
/**
* Object assignment utility
* @param target - Target object
* @param sources - Source objects
* @returns Merged object
*/
function assign<T>(target: T, ...sources: any[]): T;
/**
* Object merging utility
* @param target - Target object
* @param sources - Source objects
* @returns Merged object
*/
function merge<T>(target: Partial<T>, ...sources: Partial<T>[]): T;
/**
* Omit properties from object
* @param obj - Source object
* @param exclusions - Properties to omit
* @returns Object without omitted properties
*/
function omit<T>(obj: T, ...exclusions: (keyof T)[]): Partial<T>;
/**
* Find item in array
* @param array - Array to search
* @param predicate - Predicate function
* @returns Found item or undefined
*/
function find<T>(array: T[], predicate: (item: T, index?: number) => boolean): T | undefined;
/**
* Find index in array
* @param array - Array to search
* @param predicate - Predicate function
* @returns Found index or -1
*/
function findIndex<T>(array: T[], predicate: (item: T, index?: number) => boolean): number;
/**
* Create array of specified length
* @param size - Array size
* @param defaultValue - Default value for items
* @returns Created array
*/
function createArray<T>(size: number, defaultValue?: T): T[];
/**
* Check if arrays are equal
* @param array1 - First array
* @param array2 - Second array
* @param comparer - Optional comparer function
* @returns Whether arrays are equal
*/
function arraysEqual<T>(
array1: T[],
array2: T[],
comparer?: (item1: T, item2: T) => boolean
): boolean;
/**
* Flatten nested arrays
* @param array - Nested array
* @returns Flattened array
*/
function flatten<T>(array: (T | T[])[]): T[];
/**
* String formatting utility
* @param format - Format string
* @param values - Values to format
* @returns Formatted string
*/
function format(format: string, ...values: any[]): string;
/**
* Generate unique ID
* @param prefix - ID prefix
* @returns Unique ID string
*/
function getId(prefix?: string): string;
/**
* Get person initials from name
* @param name - Person's name
* @param isRTL - Whether RTL mode
* @param allowPhoneInitials - Allow phone number initials
* @returns Person's initials
*/
function getInitials(name?: string, isRTL?: boolean, allowPhoneInitials?: boolean): string;
/**
* Round number to precision
* @param value - Number to round
* @param precision - Decimal precision
* @returns Rounded number
*/
function precisionRound(value: number, precision: number): number;
/**
* Calculate decimal precision of number
* @param value - Number to analyze
* @returns Decimal precision
*/
function calculatePrecision(value: number): number;
/**
* Get values from object
* @param obj - Object to get values from
* @returns Array of values
*/
function values<T>(obj: { [key: string]: T }): T[];
/**
* Warning callback function
* @param message - Warning message
*/
function warn(message: string): void;
/**
* Set warning callback
* @param warningCallback - Warning callback function
*/
function setWarningCallback(warningCallback?: (message: string) => void): void;Usage Examples:
import React, { useEffect, useRef } from "react";
import {
getId,
EventGroup,
Async,
Selection,
SelectionMode,
memoizeFunction,
focusFirstChild,
KeyCodes
} from "@fluentui/react";
function UtilitiesExample() {
const eventGroupRef = useRef<EventGroup>();
const asyncRef = useRef<Async>();
const selectionRef = useRef<Selection>();
const containerId = useRef(getId('container'));
useEffect(() => {
// Initialize utilities
eventGroupRef.current = new EventGroup(this);
asyncRef.current = new Async();
selectionRef.current = new Selection({
selectionMode: SelectionMode.multiple,
onSelectionChanged: () => {
console.log('Selection changed:', selectionRef.current?.getSelection());
}
});
// Add event listeners
const handleKeyDown = (event: KeyboardEvent) => {
switch (event.which) {
case KeyCodes.escape:
console.log('Escape pressed');
break;
case KeyCodes.enter:
console.log('Enter pressed');
break;
}
};
eventGroupRef.current.on(document, 'keydown', handleKeyDown);
// Debounced function
const debouncedSave = asyncRef.current.debounce(() => {
console.log('Saving data...');
}, 500);
// Cleanup
return () => {
eventGroupRef.current?.dispose();
asyncRef.current?.dispose();
};
}, []);
// Memoized calculation
const expensiveCalculation = memoizeFunction((data: number[]) => {
console.log('Performing expensive calculation...');
return data.reduce((sum, value) => sum + value * value, 0);
});
const handleFocusFirst = () => {
const container = document.getElementById(containerId.current);
if (container) {
focusFirstChild(container);
}
};
return (
<div id={containerId.current}>
<h2>Utilities Example</h2>
<button onClick={handleFocusFirst}>
Focus First Child
</button>
<input placeholder="First focusable input" />
<input placeholder="Second focusable input" />
<div>
Calculation result: {expensiveCalculation([1, 2, 3, 4, 5])}
</div>
</div>
);
}Accessibility utility for announcing content changes to screen readers.
/**
* Component for announcing content to screen readers
* @param props - Announced properties
* @returns JSX element for screen reader announcements
*/
function Announced(props: IAnnouncedProps): JSX.Element;
interface IAnnouncedProps {
/** Message to announce */
message?: string;
/** ARIA live setting */
'aria-live'?: 'off' | 'polite' | 'assertive';
/** Custom styles */
styles?: IAnnouncedStyles;
/** Theme */
theme?: ITheme;
}Usage Examples:
import React, { useState } from "react";
import { Announced, DefaultButton } from "@fluentui/react";
function AnnouncedExample() {
const [message, setMessage] = useState('');
const [count, setCount] = useState(0);
const handleClick = () => {
const newCount = count + 1;
setCount(newCount);
setMessage(`Button clicked ${newCount} times`);
};
return (
<div>
<DefaultButton text="Click me" onClick={handleClick} />
<Announced message={message} aria-live="polite" />
<div>Count: {count}</div>
</div>
);
}Utility for implementing marquee (drag-to-select) functionality over a collection of items.
/**
* Marquee selection utility for drag-to-select functionality
* @param props - Marquee selection properties
* @returns JSX element for marquee selection
*/
function MarqueeSelection(props: IMarqueeSelectionProps): JSX.Element;
interface IMarqueeSelectionProps {
/** Selection manager */
selection: ISelection;
/** Root element selector */
rootProps?: React.HTMLAttributes<HTMLDivElement>;
/** Whether marquee is enabled */
isEnabled?: boolean;
/** Drag origin callback */
onShouldStartSelection?: (event: MouseEvent) => boolean;
/** Custom styles */
styles?: IMarqueeSelectionStyles;
/** Theme */
theme?: ITheme;
}Usage Examples:
import React from "react";
import { MarqueeSelection, Selection, DetailsList } from "@fluentui/react";
function MarqueeSelectionExample() {
const selection = new Selection({
onSelectionChanged: () => {
console.log('Selection changed:', selection.getSelection());
},
});
const items = [
{ key: '1', name: 'Item 1', value: 'A' },
{ key: '2', name: 'Item 2', value: 'B' },
{ key: '3', name: 'Item 3', value: 'C' },
];
const columns = [
{ key: 'name', name: 'Name', fieldName: 'name', minWidth: 100 },
{ key: 'value', name: 'Value', fieldName: 'value', minWidth: 100 },
];
return (
<MarqueeSelection selection={selection}>
<DetailsList
items={items}
columns={columns}
selection={selection}
selectionMode={SelectionMode.multiple}
/>
</MarqueeSelection>
);
}Utility class for implementing drag and drop functionality.
/**
* Helper class for drag and drop operations
*/
class DragDropHelper {
constructor(params: IDragDropHelperParams);
/** Subscribe to drag/drop events */
subscribe(
element: HTMLElement,
events: IDragDropEvent,
target: IDragDropTarget
): () => void;
/** Unsubscribe from events */
unsubscribe(): void;
/** Dispose of helper */
dispose(): void;
}
interface IDragDropHelperParams {
/** Selection manager */
selection: ISelection;
/** Minimum distance before drag starts */
minimumPixelsForDrag?: number;
}
interface IDragDropEvent {
/** Drag start callback */
onDragStart?: (item?: any, itemIndex?: number, selectedItems?: any[], event?: MouseEvent) => void;
/** Drag end callback */
onDragEnd?: (item?: any, event?: DragEvent) => void;
/** Drop callback */
onDrop?: (item?: any, event?: DragEvent) => void;
}
interface IDragDropTarget {
/** Whether drop is allowed */
canDrop?: (dropContext?: IDragDropContext) => boolean;
/** Drop callback */
onDrop?: (item?: any, event?: DragEvent) => void;
/** Drag enter callback */
onDragEnter?: (item?: any, event?: DragEvent) => void;
/** Drag leave callback */
onDragLeave?: (item?: any, event?: DragEvent) => void;
}Usage Examples:
import { DragDropHelper, Selection } from "@fluentui/react";
function DragDropExample() {
const selection = new Selection();
React.useEffect(() => {
const dragDropHelper = new DragDropHelper({
selection,
minimumPixelsForDrag: 5
});
const element = document.getElementById('drag-container');
if (element) {
const unsubscribe = dragDropHelper.subscribe(
element,
{
onDragStart: (item, itemIndex, selectedItems, event) => {
console.log('Drag started:', item);
},
onDragEnd: (item, event) => {
console.log('Drag ended:', item);
}
},
{
canDrop: () => true,
onDrop: (item, event) => {
console.log('Item dropped:', item);
}
}
);
return () => {
unsubscribe();
dragDropHelper.dispose();
};
}
}, []);
return (
<div id="drag-container">
<div>Drag me around!</div>
</div>
);
}