UNPKG

@base-ui/react

Version:

Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.

73 lines (71 loc) 2.13 kB
'use client'; import { isHTMLElement } from '@floating-ui/utils/dom'; import { ownerDocument } from '@base-ui/utils/owner'; import { useStableCallback } from '@base-ui/utils/useStableCallback'; import { getTarget } from "../../floating-ui-react/utils.js"; import { useRegisteredLabelId } from "../../utils/useRegisteredLabelId.js"; import { useLabelableContext } from "./LabelableContext.js"; export function useLabel(params = {}) { const { id: idProp, fallbackControlId, native = false, setLabelId: setLabelIdProp, focusControl: focusControlProp } = params; const { controlId: contextControlId, setLabelId: setContextLabelId } = useLabelableContext(); const syncLabelId = useStableCallback(nextLabelId => { setContextLabelId(nextLabelId); setLabelIdProp?.(nextLabelId); }); const id = useRegisteredLabelId(idProp, syncLabelId); const resolvedControlId = contextControlId ?? fallbackControlId; function focusControl(event) { if (focusControlProp) { focusControlProp(event, resolvedControlId); return; } if (!resolvedControlId) { return; } const controlElement = ownerDocument(event.currentTarget).getElementById(resolvedControlId); if (isHTMLElement(controlElement)) { focusElementWithVisible(controlElement); } } function handleInteraction(event) { const target = getTarget(event.nativeEvent); if (target?.closest('button,input,select,textarea')) { return; } // Prevent text selection when double clicking label. if (!event.defaultPrevented && event.detail > 1) { event.preventDefault(); } if (native) { return; } focusControl(event); } return native ? { id, htmlFor: resolvedControlId ?? undefined, onMouseDown: handleInteraction } : { id, onClick: handleInteraction, onPointerDown(event) { event.preventDefault(); } }; } export function focusElementWithVisible(element) { element.focus({ // Available from Chrome 144+ (January 2026). // Safari and Firefox already support it. focusVisible: true }); }