Shared utilities for data-slot headless UI components.
npm install @data-slot/coreQuery a single part/slot within a component root.
const trigger = getPart<HTMLButtonElement>(root, "dialog-trigger");Query all parts/slots within a component root.
const items = getParts<HTMLElement>(root, "accordion-item");Find all component roots within a scope by data-slot value.
const dialogs = getRoots(document, "dialog");Ensure an element has an id, generating one if needed.
const id = ensureId(content, "dialog-content");
// Returns existing id or generates "dialog-content-1"Set or remove an ARIA attribute. Boolean values are converted to strings.
setAria(trigger, "expanded", true); // aria-expanded="true"
setAria(trigger, "expanded", null); // removes aria-expandedLink content element to its label and description via ARIA.
linkLabelledBy(dialogContent, titleElement, descriptionElement);
// Sets aria-labelledby and aria-describedbyAdd an event listener and return a cleanup function.
const cleanup = on(button, "click", () => console.log("clicked"));
// Later: cleanup() to remove listenerDispatch a custom event with optional detail.
emit(root, "tabs:change", { value: "tab-2" });Compose multiple event handlers into one. Stops if event.defaultPrevented.
const handler = composeHandlers(onClickProp, internalHandler);This package is used internally by all @data-slot/* component packages. You typically don't need to import it directly unless building custom components.
import { getPart, setAria, on } from "@data-slot/core";
function createCustomComponent(root: Element) {
const trigger = getPart(root, "custom-trigger");
const content = getPart(root, "custom-content");
const cleanup = on(trigger, "click", () => {
const isOpen = content.hidden;
content.hidden = !isOpen;
setAria(trigger, "expanded", isOpen);
});
return { destroy: cleanup };
}MIT