Essential utility functions and React hooks for building accessible React Aria UI components
npx @tessl/cli install tessl/npm-react-aria--utils@3.30.0Essential utility functions and React hooks that serve as the foundational building blocks for React Aria's accessible UI component library. This package provides critical utilities for DOM manipulation, platform detection, React lifecycle management, accessibility features, and animation helpers.
npm install @react-aria/utilsimport {
useId,
mergeProps,
filterDOMProps,
focusWithoutScrolling,
isMac,
useEvent,
useSyntheticLinkProps
} from "@react-aria/utils";For CommonJS:
const {
useId,
mergeProps,
filterDOMProps,
focusWithoutScrolling,
isMac,
useEvent,
useSyntheticLinkProps
} = require("@react-aria/utils");import { useId, mergeProps, filterDOMProps, isMac } from "@react-aria/utils";
function MyComponent({ className, onClick, ...props }) {
// Generate unique IDs for accessibility
const labelId = useId();
// Merge props intelligently
const buttonProps = mergeProps(
{
id: useId(),
className: "button",
onClick: (e) => console.log("default click")
},
{
className,
onClick,
"aria-labelledby": labelId
}
);
// Filter props for DOM elements
const domProps = filterDOMProps(props, { labelable: true });
// Platform-specific behavior
const shortcutKey = isMac() ? "⌘" : "Ctrl";
return (
<div>
<label id={labelId}>My Button ({shortcutKey}+K)</label>
<button {...buttonProps} {...domProps}>
Click me
</button>
</div>
);
}React Aria Utils is organized around several key functional areas:
Core utilities for generating accessible IDs and managing React refs across components.
function useId(defaultId?: string): string;
function mergeIds(idA: string, idB: string): string;
function useSlotId(depArray?: ReadonlyArray<any>): string;
function mergeRefs<T>(...refs: (Ref<T> | null | undefined)[]): Ref<T>;
function useObjectRef<T>(ref?: ForwardedRef<T>): MutableRefObject<T | null>;Intelligent prop merging, event chaining, and DOM attribute filtering for React components.
function mergeProps<T extends Props[]>(...args: T): UnionToIntersection<TupleTypes<T>>;
function chain(...callbacks: any[]): (...args: any[]) => void;
function filterDOMProps(props: DOMProps, opts?: FilterDOMPropsOptions): DOMAttributes;
interface FilterDOMPropsOptions {
labelable?: boolean;
isLink?: boolean;
global?: boolean;
events?: boolean;
propNames?: Set<string>;
}Browser and device identification utilities for conditional behavior and platform-specific features.
function isMac(): boolean;
function isIPhone(): boolean;
function isIPad(): boolean;
function isIOS(): boolean;
function isAppleDevice(): boolean;
function isWebKit(): boolean;
function isChrome(): boolean;
function isAndroid(): boolean;
function isFirefox(): boolean;Focus management, element accessibility checks, and ARIA labeling utilities.
function focusWithoutScrolling(element: FocusableElement): void;
function isFocusable(element: Element): boolean;
function isTabbable(element: Element): boolean;
function useLabels(props: AriaLabelingProps, defaultLabel?: string): DOMProps & AriaLabelingProps;
function useDescription(description: string | undefined): DOMProps & AriaLabelingProps;
interface AriaLabelingProps {
"aria-label"?: string;
"aria-labelledby"?: string;
"aria-describedby"?: string;
}Cross-platform event handling with automatic cleanup and stable function references.
function useEvent<K extends keyof GlobalEventHandlersEventMap>(
ref: RefObject<EventTarget | null>,
event: K,
handler?: (this: Document, ev: GlobalEventHandlersEventMap[K]) => any,
options?: AddEventListenerOptions
): void;
interface GlobalListeners {
addGlobalListener<K extends keyof DocumentEventMap>(
el: EventTarget,
type: K,
listener: (this: Document, ev: DocumentEventMap[K]) => any,
options?: AddEventListenerOptions | boolean
): void;
removeGlobalListener<K extends keyof DocumentEventMap>(
el: EventTarget,
type: K,
listener: (this: Document, ev: DocumentEventMap[K]) => any,
options?: EventListenerOptions | boolean
): void;
removeAllGlobalListeners(): void;
}
function useGlobalListeners(): GlobalListeners;
function useEffectEvent<T extends Function>(fn?: T): T;Viewport tracking, scroll utilities, element positioning, and resize observation.
function getScrollParent(node: Element, checkForOverflow?: boolean): Element;
function getScrollParents(node: Element): Element[];
function isScrollable(element: Element, checkForOverflow?: boolean): boolean;
function scrollIntoView(scrollView: HTMLElement, element: HTMLElement): void;
function scrollIntoViewport(targetElement: Element, opts?: { containingElement?: Element }): void;
interface ViewportSize {
width: number;
height: number;
}
function useViewportSize(): ViewportSize;
function useResizeObserver<T extends Element>(options: {
ref: RefObject<T>;
box?: ResizeObserverBoxOptions;
onResize: () => void;
}): void;Client-side routing integration, synthetic link handling, and programmatic navigation.
interface Router {
isNative: boolean;
open: (target: HTMLAnchorElement, modifiers: Modifiers, setOpening?: boolean) => void;
useHref?: (href: string) => string;
}
function RouterProvider(props: { navigate: (path: string) => void; useHref?: (href: string) => string; children: ReactNode }): JSX.Element;
function useRouter(): Router;
function openLink(target: HTMLAnchorElement, modifiers: Modifiers, setOpening?: boolean): void;
function shouldClientNavigate(link: HTMLAnchorElement, modifiers: Modifiers): boolean;
function useSyntheticLinkProps(props: LinkDOMProps): DOMAttributes<HTMLElement>;
function useLinkProps(props?: LinkDOMProps): LinkDOMProps;
interface Modifiers {
metaKey: boolean;
ctrlKey: boolean;
altKey: boolean;
shiftKey: boolean;
}Enter/exit animation management with CSS integration and transition coordination.
function useEnterAnimation(ref: RefObject<HTMLElement>, isReady?: boolean): boolean;
function useExitAnimation(ref: RefObject<HTMLElement>, isOpen: boolean): boolean;
function runAfterTransition(fn: () => void): void;Custom React hooks for lifecycle management, state synchronization, and optimized effects.
function useUpdateEffect(effect: EffectCallback, deps?: DependencyList): void;
function useUpdateLayoutEffect(effect: EffectCallback, deps?: DependencyList): void;
function useLayoutEffect: typeof React.useLayoutEffect;
function useValueEffect<T>(defaultValue: T): [T, (value: T | (() => Generator<T>)) => void];
function useDeepMemo<T>(value: T, isEqual?: (a: T, b: T) => boolean): T;
function useFormReset<T>(ref: RefObject<HTMLFormElement | HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>, initialValue: T, onReset: (value: T) => void): void;Detection and handling of virtual events from assistive technology and keyboard navigation.
function isVirtualClick(event: MouseEvent | PointerEvent): boolean;
function isVirtualPointerEvent(event: PointerEvent): boolean;
function isCtrlKeyPressed(e: KeyboardEvent | MouseEvent | PointerEvent): boolean;Complete shadow DOM traversal, manipulation, and compatibility utilities.
class ShadowTreeWalker implements TreeWalker {
// Full TreeWalker interface implementation
}
function createShadowTreeWalker(
doc: Document,
root: Node,
whatToShow?: number,
filter?: NodeFilter | null
): TreeWalker;
function getActiveElement(doc?: Document): Element | null;
function getEventTarget<T extends Event>(event: T): Element | null;
function nodeContains(node: Node, otherNode: Node): boolean;Utilities for implementing infinite scrolling, pagination, and load-more functionality.
function useLoadMore(props: LoadMoreProps, ref: RefObject<HTMLElement | null>): void;
function useLoadMoreSentinel(
props: LoadMoreSentinelProps,
ref: RefObject<HTMLElement | null>
): void;
// Experimental alias
function UNSTABLE_useLoadMoreSentinel(
props: LoadMoreSentinelProps,
ref: RefObject<HTMLElement | null>
): void;
interface LoadMoreProps {
isLoading?: boolean;
onLoadMore?: () => void;
scrollOffset?: number;
items?: any;
}
interface LoadMoreSentinelProps extends Omit<AsyncLoadable, 'isLoading'> {
collection: Collection<any>;
onLoadMore?: () => void;
scrollOffset?: number;
}Additional utilities for DOM helpers, value management, drag gestures, and utility functions.
function getOffset(element: Element, reverse?: boolean, orientation?: "horizontal" | "vertical"): number;
function getOwnerDocument(el: Element): Document;
function getOwnerWindow(el: Element): Window;
function isShadowRoot(node: Node): node is ShadowRoot;
function inertValue<T>(value: T): T;
// Deprecated drag utility
function useDrag1D(props: object): HTMLAttributes<HTMLElement>;
// Constants
const CLEAR_FOCUS_EVENT = "react-aria-clear-focus";
const FOCUS_EVENT = "react-aria-focus";
// Re-exported from @react-stately/utils
function clamp(value: number, min: number, max: number): number;
function snapValueToStep(value: number, step: number, min?: number): number;interface DOMProps {
id?: string;
}
interface AriaLabelingProps {
"aria-label"?: string;
"aria-labelledby"?: string;
"aria-describedby"?: string;
}
interface LinkDOMProps extends DOMProps {
href?: string;
target?: string;
rel?: string;
download?: boolean | string;
ping?: string;
referrerPolicy?: string;
}
interface LoadMoreProps {
isLoading?: boolean;
onLoadMore?: () => void;
scrollOffset?: number;
items?: any;
}
interface AsyncLoadable {
isLoading?: boolean;
onLoadMore?: () => any;
}
interface LoadMoreSentinelProps extends Omit<AsyncLoadable, 'isLoading'> {
collection: Collection<any>;
onLoadMore?: () => void;
scrollOffset?: number;
}
interface Collection<T> {
// Collection interface from @react-types/shared - provides methods for managing collections of items
}
type FocusableElement = HTMLElement | SVGElement;
interface ViewportSize {
width: number;
height: number;
}