OverviewGetting startedInstallationFramework guidesComponentsFoundationsCore and stateTheming and layoutAgent toolingAI toolingChange impactRecipesArchitectureRoadmapHelp and releasesGetting startedInstallationCore and stateGuidesRecipes

npm

Install the packages you use; each one brings only its own dependencies.

Oddkin packages
PackageWhat it is for
@oddkin/aiOptional AI interaction elements, headless controllers, and stream adapters for conversation, inline assistance, research, and agent workflows.
@oddkin/analyzerNode-only static analysis of Oddkin component libraries: Custom Elements Manifest and oddkin.metadata.json, without executing component code, and the agent kits generated from them.
@oddkin/appOptional application lifetime, router, and async resources.
@oddkin/componentsThemed custom elements, Oddkin layout presets, and component metadata.
@oddkin/coreAuthoring foundation: reactive primitives, Scope, OddkinElement, templates, styles, layout recipes, collections, models, registration.
@oddkin/stateOptional stores, selectors, context, persistence, and inspection.
@oddkin/tokensTheme configuration, pure token generation, and CSS, JSON, DTCG, and TypeScript outputs. Browser entry points are DOM-free.
@oddkin/workbenchMetadata-driven documentation tooling. DOM-free example, configuration, page-registry, data-file, and conformance contracts; a test-runner integration.
Terminal
npm install @oddkin/tokens@beta @oddkin/core@beta @oddkin/components@beta

The packages are in beta: the @beta tag installs the current beta, and contracts may still change before 1.0.0.

With a bundler

For an app built with Vite or another bundler, start from the bundler’s own template, then install the packages. With Vite and TypeScript:

Terminal
npm create vite@latest my-app -- --template vanilla-ts
cd my-app
npm install @oddkin/tokens@beta @oddkin/core@beta @oddkin/components@beta

Import the theme stylesheet and the elements you use from the entry module (src/main.ts in that template). The bundler resolves both, so there is no import map or node_modules link to write.

JavaScript
import '@oddkin/tokens/css/default.css';
import '@oddkin/components/define/button';

Then write the elements in the page’s HTML, as Components in any app shows.

Native ES modules and import maps

Every entry is a standard ES module with bare imports, so a page can load the packages without a bundler. An import map lists one URL per exported entry: entries map to different files (@oddkin/components/define/button is dist/button/button.define.js), so a prefix mapping is not enough.

HTML
<script type="importmap">
  {
    "imports": {
      "@oddkin/core/element": "/node_modules/@oddkin/core/dist/prod/element/index.js",
      "@oddkin/core/reactive": "/node_modules/@oddkin/core/dist/prod/reactive/index.js",
      "@oddkin/core/styles": "/node_modules/@oddkin/core/dist/prod/styles/index.js",
      "@oddkin/core/template": "/node_modules/@oddkin/core/dist/prod/template/index.js",
      "@oddkin/tokens/refs": "/node_modules/@oddkin/tokens/dist/refs/index.js",
      "@oddkin/components/define/button": "/node_modules/@oddkin/components/dist/button/button.define.js"
    }
  }
</script>
<script type="module">
  import '@oddkin/components/define/button';
</script>

These are the six entries odd-button loads. Other elements import further entries: list each one the browser reports as unresolved, or generate the map from the packages’ exports with createImportMap() from @oddkin/workbench/data. The links point into node_modules, so serve the page from the project’s root with any static file server. examples/components-only in the repository is a complete page with its map and a strict Content Security Policy.

Packages that carry development diagnostics publish two builds: the development export condition names dist/ (with the diagnostics) and default names dist/prod/. Bundlers pick the condition for you; a hand-written map chooses one.

TypeScript and plain JavaScript

Every package ships declaration files, and each element registers its tag in HTMLElementTagNameMap, so document.querySelector('odd-button') is typed. Plain JavaScript uses the same entries.

TypeScript
import '@oddkin/components/define/button';

const button = document.querySelector('odd-button');
if (button) button.disabled = true;

Supported browsers

Supported browsers (checked 2026-10-26)
BrowserVersion
Chrome130 and later
Chrome for Android130 and later
Edge130 and later
Firefox132 and later
Firefox for Android132 and later
Safari18.2 and later
Safari on iOS18.2 and later

Browser support lists what each platform feature needs and how it falls back.