Start here
Installation
Install from npm, or load the packages as native ES modules through an import map. Types ship with every package.
npm
Install the packages you use; each one brings only its own dependencies.
| Package | What it is for |
|---|---|
@oddkin/ai | Optional AI interaction elements, headless controllers, and stream adapters for conversation, inline assistance, research, and agent workflows. |
@oddkin/analyzer | Node-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/app | Optional application lifetime, router, and async resources. |
@oddkin/components | Themed custom elements, Oddkin layout presets, and component metadata. |
@oddkin/core | Authoring foundation: reactive primitives, Scope, OddkinElement, templates, styles, layout recipes, collections, models, registration. |
@oddkin/state | Optional stores, selectors, context, persistence, and inspection. |
@oddkin/tokens | Theme configuration, pure token generation, and CSS, JSON, DTCG, and TypeScript outputs. Browser entry points are DOM-free. |
@oddkin/workbench | Metadata-driven documentation tooling. DOM-free example, configuration, page-registry, data-file, and conformance contracts; a test-runner integration. |
npm install @oddkin/tokens@beta @oddkin/core@beta @oddkin/components@betaThe 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:
npm create vite@latest my-app -- --template vanilla-ts
cd my-app
npm install @oddkin/tokens@beta @oddkin/core@beta @oddkin/components@betaImport 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.
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.
<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.
import '@oddkin/components/define/button';
const button = document.querySelector('odd-button');
if (button) button.disabled = true;Supported browsers
| Browser | Version |
|---|---|
| Chrome | 130 and later |
| Chrome for Android | 130 and later |
| Edge | 130 and later |
| Firefox | 132 and later |
| Firefox for Android | 132 and later |
| Safari | 18.2 and later |
| Safari on iOS | 18.2 and later |
Browser support lists what each platform feature needs and how it falls back.