@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
JavaScript
'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
});
}