This repository contains the source code and documentation for Base UI: a headless, unstyled React component library.
- Source code for components and private utils is in
packages/react/. - Source code for public shared utils is in
packages/utils/. - Experiments are located at
docs/src/app/(private)/experiments/. Use for creating demos that require manual testing in the browser. - Public documentation is located at
docs/src/app/(public)/(content)/react/. Alter the docs where necessary when changes must be visible to library users. - When creating public demos on the docs, refer to the
herodemo for the given component and largely follow its styles (both CSS Modules and Tailwind CSS versions). Other demos may also contain relevant styling. Do not add custom styling beyond the critical layout styles necessary for new demos.
- Always use the
useTimeoututility from@base-ui-components/utils/useTimeoutinstead ofwindow.setTimeout, anduseAnimationFramefrom@base-ui-components/utils/useAnimationFrameinstead ofrequestAnimationFrame. Search for other example usage in the codebase if unsure how to use them. - Use the
useEventCallbackutility from@base-ui-components/utils/useEventCallbackinstead ofReact.useCallbackif the function is called within an effect or event handler. The utility cannot be used to memoize functions that are called directly in the body of a component (during render), so continue withReact.useCallbackin those scenarios. - Always use the
useIsoLayoutEffectutility from@base-ui-components/utils/useIsoLayoutEffectinstead ofReact.useLayoutEffect. - Avoid duplicating logic where necessary. If two components can share logic (such as event handlers), define the logic/handlers in the parent and share it through a context to the child; use the existing context if it exists.
- Do not randomly cast (for example
as any) if there are no type errors without doing so. Runpnpm typescriptto verify types. - Ensure your changes pass linting - run
pnpm eslint. - Ensure your changes are formatted correctly - run
pnpm prettier.
- Run tests in JSDOM env with
pnpm test:jsdom {name} --no-watchsuch aspnpm test:jsdom NumberField --no-watchorpnpm test:jsdom parse --no-watch. - Run tests in Chromium env with
pnpm test:chromium {name} --no-watchsuch aspnpm test:chromium NumberField --no-watchorpnpm test:jsdom parse --no-watch. - If you made changes to the source code, ensure you verify your changes by running tests (see above), and writing new tests where applicable. If tests require the browser because, for example, they require layout measurements, restrict it to the Chromium env by using
it.skipIf(isJSDOM)ordescribe.skipIf(isJSDOM)(search other tests for example usage if unsure). - Follow the established conventions in existing tests. Each file/component is tested with the filename
name.test.tsx. For example,PopoverRoot.test.tsxis next to its source filePopoverRoot.tsx. - Tests use
chai'sexpectand Sinon'sspy(), do not assume they have methods of other libraries' APIs. Search existing tests for example usage if unsure.
- Commit messages follow the format
[scope] Imperative summary(for example[popover] Fix focus trap). Choose scopes that mirror package or component names that were changed. - Use
[all components]scope for changes that broadly affect most components.