42-components
v0.0.2
Published
Headless UI component library (vanilla TypeScript) with optional theme.
Readme
@42-components
Headless UI component library in vanilla TypeScript, with optional theme.
Packages
| Package | Description |
| --- | --- |
| @42/core | Framework-agnostic headless controllers (subpath exports per component). |
| @42/styles | Optional theme (CSS custom properties, dark mode included). |
Components
Grouped by what you are trying to do. Full per-component reference (markup,
options, events) lives in docs/llm/reference/; complex
components have a deep dive in docs/llm/.
| Category | Use it when… | Reference | | --- | --- | --- | | Inputs & Forms | you capture data from the user | inputs.md | | Overlays | you need a transient layer above content | overlays.md | | Navigation | you move around or structure a flow | navigation.md | | Data & Collections | you display or manipulate sets of data | data.md | | Media | you show images or people | media.md | | Feedback & Status | you communicate state, progress or an action | feedback.md | | Disclosure & Layout | you show or hide regions of content | disclosure.md | | Presentational (CSS-only) | you just need styles, no controller | presentational.md |
Development
pnpm install
pnpm test # vitest (jsdom)
pnpm build # build all publishable packages
pnpm storybook # run Storybook (HTML + Vite)Usage
npm install @42/core @42/styles<div data-c42-accordion>
<div data-c42-accordion-item data-value="a">
<button data-c42-accordion-trigger>Title</button>
<div data-c42-accordion-panel>Content</div>
</div>
</div>import { Accordion } from '@42/core/accordion';
import '@42/styles/accordion.css'; // optional theme
const acc = new Accordion(document.querySelector('[data-c42-accordion]')!, { multiple: false });
acc.on('accordion:change', (e) => console.log(e.detail.value));Form validation
The Form controller turns native inputs into a validated, accessible form
(ARIA wiring, error states, typed events) without imposing styles:
<form data-c42-form>
<div data-c42-field>
<label for="email">Email</label>
<input id="email" name="email" type="email" data-c42-validate="required email" />
<span data-c42-field-error hidden></span>
</div>
<button type="submit">Sign up</button>
</form>import { Form } from '@42/core/form';
import '@42/styles/form.css'; // optional theme
const form = new Form(document.querySelector('[data-c42-form]')!, { mode: 'blur' });
form.on('form:submit', (e) => console.log(e.detail.values)); // only fires when valid
form.on('form:invalid', (e) => console.log(e.detail.errors));See docs/llm/form.md for rules, options and recipes.
Theming
Import @42/styles for the complete theme. Customize by overriding primitives:
:root {
--c42-primary-500: #0ea5e9;
--c42-primary-600: #0284c7;
}Dark mode activates automatically via prefers-color-scheme or with data-theme="dark" on <html>.
The full theme also applies a thin, subtle global scrollbar (tunable via
--c42-scrollbar-size / --c42-scrollbar-thumb / --c42-scrollbar-thumb-hover,
or import @42/styles/scrollbar.css standalone).
AI agents
See LLM.md for the complete component reference optimized for AI consumption.
