---
title: Packages and entrypoints
description: Every published import, what it contains, and whether it is safe on the server.
editUrl: true
head: []
template: doc
sidebar:
  order: 1
  hidden: false
  attrs: {}
pagefind: true
draft: false
---

## Packages

| Package                  | Role                                                                                                                                                                                                  |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `@timelessui/components` | Everything a consumer needs to build an interface: CSS, custom elements, contracts, and utilities. This is the only package you install for components.                                               |
| `@timelessui/color`      | CSS color parsing, conversion, gamut, and contrast utilities. It depends on nothing, and arrives as a dependency of the components; install it directly only if you want the color math without them. |
| `@timelessui/core`       | The internal custom-element authoring layer the components are built on. It arrives as a dependency; you do not import it directly, and it is not part of the public API.                             |

```bash
pnpm add @timelessui/components
```

## Entrypoints

| Import                                                         | Contains                                                                                         | Side effects                  |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ----------------------------- |
| `@timelessui/components`                                       | Contracts, design-token names, permitted attribute values, event types, and every element class. | None                          |
| `@timelessui/components/{element}`                             | One enhanced element's class and helpers, for example `@timelessui/components/dialog`.           | None                          |
| `@timelessui/components/register/ui-{element}`                 | Registers one custom element as it is imported.                                                  | Calls `customElements.define` |
| `@timelessui/components/register`                              | Registers every public custom element as it is imported.                                         | Calls `customElements.define` |
| `@timelessui/components/define/ui-{element}`                   | One `define{Element}Element()` function. Registers nothing until you call it.                    | None                          |
| `@timelessui/components/define`                                | Every define function, plus `defineTimelessElements()`. Registers nothing until you call it.     | None                          |
| `@timelessui/components/css/tokens.css`                        | The cascade-layer order and `color-scheme`. Required, and imported first.                        | Stylesheet                    |
| `@timelessui/components/css/core/{component}.css`              | One component's behavior: anchoring, box participation, scrolling, native resets. Required.      | Stylesheet                    |
| `@timelessui/components/css/core.css`                          | Every `core/` file. Required, and the tier you keep when you replace the theme.                  | Stylesheet                    |
| `@timelessui/components/css/themes/atmosphere/tokens.css`      | Every `--ui-*` value. Required by any Atmosphere component file, which carries no fallbacks.     | Stylesheet                    |
| `@timelessui/components/css/themes/atmosphere/{component}.css` | One component's look. Optional — this is the tier you replace.                                   | Stylesheet                    |
| `@timelessui/components/css/themes/atmosphere.css`             | The required tiers plus every Atmosphere stylesheet. The one import a prototype needs.           | Stylesheet                    |
| `@timelessui/components/collection`                            | Locale-aware matching and disabled-aware keyboard navigation.                                    | None                          |
| `@timelessui/color`                                            | Color parsing, serialization, conversion, gamut, and WCAG contrast. Its own package.             | None                          |
| `@timelessui/components/events`                                | Transition event and detail types.                                                               | None                          |
| `@timelessui/components/value-state`                           | Authored-default and live-value helpers.                                                         | None                          |
| `@timelessui/components/attributes`                            | Typed attribute builder for CSS-only components.                                                 | None                          |
| `@timelessui/components/validate`                              | Development-time check that authored markup matches the contracts.                               | None                          |
| `@timelessui/components/react`                                 | React 19 intrinsic-element declarations. Types only.                                             | None                          |
| `@timelessui/components/preact`                                | Preact intrinsic-element declarations. Types only.                                               | None                          |
| `@timelessui/components/solid`                                 | Solid intrinsic-element declarations. Types only.                                                | None                          |
| `@timelessui/components/vue`                                   | Vue `GlobalComponents` declarations. Types only.                                                 | None                          |
| `@timelessui/components/svelte`                                | Svelte `svelteHTML.IntrinsicElements` declarations. Types only.                                  | None                          |

Only enhanced elements have a class entrypoint. CSS-only primitives such as Button, Alert, and Card
are classes and attributes rather than JavaScript, so they have no per-component module at all —
their permitted values live on the root import instead. Two pairs share one module behind two
subpaths, so importing either name gives you both classes: `radio-group` and `checkbox-group` are
both `choice-group`, and `toaster` and `toast` are both `toast`.

## What an entrypoint weighs

Enhanced elements are composed, so an entrypoint pulls the modules it is built on. Select contains
Listbox, the option layer, Popover, and the anchoring layer, which is why it is the heaviest single
import in the package.

Bundled and minified, `@timelessui/components/select` is about 13.5 kB gzipped. Adding
`@timelessui/components/combobox` to the same page brings the pair to about 16 kB rather than to the
sum of the two, because everything under both of them is shared. Six enhanced elements — Select,
Combobox, Listbox, Popover, Menu, and Dialog — come to about 21 kB together. There is no framework
runtime underneath any of it, and a CSS-only component such as Button or Card adds no JavaScript at
all.

Those are measurements rather than budgets, taken with esbuild at default settings; your bundler
will land somewhere nearby. The package ships unminified so your own pipeline decides.

## Contracts and permitted values

The root import is the machine-readable version of every component reference page:

```ts
import { buttonVariants, componentContracts } from '@timelessui/components'

buttonVariants
// ['primary', 'secondary', 'outline', 'ghost', 'danger', 'danger-outline', 'link']

componentContracts.tabs.parts.filter((part) => part.required).map((part) => part.selector)
// ["[role='tablist']", "[role='tab']", "[role='tabpanel']"]
```

`componentContracts` records each component's root, stylesheets, attributes with their permitted
values and defaults, authored parts, public state, and events. Every attribute that takes a fixed
set of values also names the array that set is exported as, in its `set` field.

The build proves those values against the stylesheets in both directions: a value a stylesheet
selects must be declared, and a declared value must be selected or be the default, which is the base
rule and so has no selector of its own. `pnpm -F @timelessui/components run contracts:validate`
fails either way, which is why the reference tables cannot drift from the CSS.

Permitted values are also exported individually as `as const` arrays with matching union types, each
declared exactly once and generated from the same source as the contracts: `buttonVariants`,
`buttonSizes`, `alertVariants`, `spinnerVariants`, `badgeVariants`, `avatarShapes`,
`avatarStatuses`, `cardVariants`, `linkVariants`, `listVariants`, `separatorVariants`,
`separatorOrientations`, `skeletonShapes`, `skeletonWidths`, `groupOrientations`, `primitiveSizes`,
`primitiveDensities`, `compactDensities`, `tableAlignments`, `breadcrumbSeparators`,
`formControlSizes`, `fieldLayouts`, `formDensities`, `choiceGroupOrientations`,
`floatingPlacements`, `tabsOrientations`, `tabsActivations`, `dialogKinds`, `sheetPositions`,
`popoverRoles`, `hoverCardVariants`, `menuOrientations`, `toolbarOrientations`,
`collectionAlignments`, `optionFilterModes`, `toasterPlacements`, `toasterStacks`,
`toggleGroupOrientations`, `toggleGroupSelections`, and `colorPickerFormats`.

Arrays with identical values keep separate names because they are separate public exports.
`buttonSizes`, `primitiveSizes`, and `formControlSizes` are all `sm | md | lg`, and each names the
set its own components implement.

## Design tokens

`uiTokenGroups` names every public custom property, grouped by purpose, and `isUIToken` narrows a
string against the set. Both name the theme-neutral `--ui-*` vocabulary rather than Atmosphere,
which is one set of values for it. See [Theming](/docs/styling/theming/) for the values and how to
override them.

## Custom Elements Manifest

`@timelessui/components/custom-elements.json` is exposed through the package's `customElements`
field. It declares attributes with union types and defaults, reflecting properties under their real
names, events with the detail type each element actually dispatches, CSS custom properties, and
custom states — for editors, generators, and downstream tooling.

Authored parts appear under a namespaced `timeless:parts` key rather than the manifest's `cssParts`,
each with the selector it is addressed by. `cssParts` describes `::part()`, which only crosses a
shadow boundary; Timeless anatomy is Light DOM you author yourself, so `[data-ui-part~='trigger']`
is the real contract and claiming a shadow one would be wrong.

## Framework typings

Every framework typing is generated from the manifest and is types-only: importing one adds no
runtime code, no wrapper, and no dependency on that framework. Import the one you need once in your
application types.

| Import                          | Augments                                |
| ------------------------------- | --------------------------------------- |
| `@timelessui/components/react`  | `react` and `react/jsx-runtime` `JSX`   |
| `@timelessui/components/preact` | `preact` and `preact/jsx-runtime` `JSX` |
| `@timelessui/components/solid`  | `solid-js` `JSX`                        |
| `@timelessui/components/vue`    | `@vue/runtime-dom` `GlobalComponents`   |
| `@timelessui/components/svelte` | `svelteHTML.IntrinsicElements`          |

Each declares, per element, the attributes an author writes typed to their permitted values, the DOM
properties those attributes reflect under the element's real property names, and the element's own
events with its own detail type. `data-*` and `aria-*` stay open as an escape hatch.

Two boundaries worth knowing:

- **React 19 is required** for `on*` event props on custom elements and for non-string attribute
  values. On React 18 the declarations still type your markup; pass primitives as attributes and
  bind events with a ref.
- **Angular** has no type-level checking for unknown elements beyond `CUSTOM_ELEMENTS_SCHEMA`, which
  disables checking rather than adding it. There is nothing to ship for Angular, so nothing is
  shipped. Timeless elements work there; their attributes are simply unchecked.

Qwik is not covered. Its JSX module moved between major versions and its custom-event prop
convention differs from the frameworks above, so no declaration is published rather than one that
might be wrong.

## Authoring CSS-only components

`ui-*` tags are tags, so every typing above and the editor data complete them precisely. CSS-only
components are a root class plus `data-ui-*` on a native tag, which no editor can complete per
element. `@timelessui/components/attributes` is the typed answer: `uiAttributes` returns the
attribute object and `uiAttributeString` the serialized form, both keyed to each component's
permitted values. Neither is reachable from the default import.

See [Editor setup](/docs/getting-started/editor-setup/#the-one-gap-css-only-components) for why the
gap exists, worked examples, and the development-time validator.

## Server rendering

Every import above is side-effect free except the stylesheets and the `register/*` entrypoints.
Class imports and `define/*` imports never call `customElements.define`, so they are safe in server
code and test utilities — `define/*` hands you the function and leaves the calling to you.

`register/*` is the one that registers on import, and it is inert on the server, where there is no
`customElements` to define into. That is deliberate: a universal module can import it without
crashing the render, and the client bundle re-imports the same module and registers for real. The
consequence is worth stating plainly — a `register/*` import that only ever executes on the server
registers nothing at all, so it belongs in code the browser loads. When you would rather be explicit
about the timing, import `define/*` and call the function yourself.

See [Core concepts](/docs/concepts/) for what registration does in a browser realm.