Architecture (consumer view)
Sometic is a portable application behavior system: shared controllers for UI, forms, auth, HTTP, query (server state), and document head, with thin framework adapters and your styling system. It is not a visual component library that owns your look and feel.
Product promise: one behavior model, every supported JavaScript stack, your design system.
Mental model
Think in four layers. Dependencies flow one way only: adapters and integrations depend on features; features depend on foundation; foundation never imports frameworks or apps.
Consumer app
│
▼
Framework adapters (react, vue, elements, …)
│
▼
Feature packages (forms, auth, http, query, theme, dom, …)
│
▼
Foundation (core, events, store, styling, accessibility, date-core)Optional peers (auth providers, date libraries, Immer) sit beside features. They never become hard dependencies of foundation packages.
What ships where
| Layer | Examples | You install when… |
|---|---|---|
| Foundation | @sometic/core, events, store, styling, accessibility | You need shared contracts, state, or styling hooks |
| Features | theme, validation, forms, auth, http, query, head, dom | You need product behavior (forms, sessions, fetches, SEO) |
| Integrations | elements, auth-local, date-native, … | You want custom elements or a concrete provider |
| Adapters | react, vue, Wave B/C packages | You bind engines to a UI framework |
| Tooling | cli, registry | You scaffold or add templates |
Prefer subpath imports (@sometic/react/button) so unused surfaces stay out of the bundle. See Tree shaking.
Component pattern
Every interactive family follows the same shape:
- Behavior engine (framework-independent): state, events, a11y attributes, slots contract.
- Styling resolution: classes, styles, CSS variables, stable
data-*state attributes. - Framework adapter: thin props, refs, slots, and lifecycle binding.
- Optional theme: tokens and CSS variables when you opt in; never required.
Adapters must not reimplement business logic. If React and Vue diverge in behavior, that is a bug.
Runtime guarantees
SSR-safe imports: packages do not read window, document, localStorage, matchMedia, or customElements at import time. Create controllers and register elements in browser or effect code.
Explicit state: no hidden module-level singletons for app state. You create stores, forms, and auth clients; you dispose them when done.
Native semantics first: real <button>, <input>, <form>, focus, keyboard, autofill, and labels stay primary. High-level events exist only where native events are insufficient.
Multi-root safe: multiple app roots on one page can each own their own store, theme controller, and auth client.
Auth, HTTP, and Query
UI / route guards (UX only)
▼
auth core (session, refresh coordination, capabilities)
▼
http client (interceptors, queue-after-refresh)
▼
query client (keys, cache, invalidate / optimistic mutate)
▼
UI adapters (React / Vue / Vanilla observers)Transport and 401 refresh live on HTTP + auth. Provider adapters (auth-local, Firebase, Supabase, OIDC) plug into auth core — they never become HTTP or query dependencies. Server data stays in @sometic/query, not @sometic/store. After re-auth, invalidate or refetch active queries. Your backend remains the authorization enforcement boundary. See Authentication, HTTP, and Query.
Delivery surfaces
| Surface | Role |
|---|---|
npm packages (@sometic/*) | Maintained logic, types, updates |
| CLI + registry | Explicit init / add (no interactive postinstall) |
| Docs site | Consumer guides and maturity labels |
Stability honesty
Public beta labels live on Beta maturity. In short:
- Beta: Wave A foundations, forms, auth, HTTP, query, React, Vue, Elements, CLI.
- Experimental: Wave B (Angular, Svelte, Solid, Preact) and Wave C (Alpine, jQuery, HTMX) contracts.
- Deferred: later-phase catalogs such as multi-select polish, date/time picker UI, command palette, and data tables. Menu, Combobox, Drawer, Tabs, and related launch surfaces ship in this beta — see What’s included.
When to use Sometic
Use when you want one behavior model across React, Vue, and vanilla/custom elements, with your own CSS system and optional tokens.
Do not use when you need a full design-system skin out of the box, or when you only need a single framework-specific widget with no shared engine.
FAQ
Why engines separate from adapters? So behavior is tested once and frameworks stay thin. Fixing a focus-trap or validation race in the engine benefits every adapter.
Why not ship Tailwind or Bootstrap inside cores? Styling must stay consumer-owned. Pass class names; optionally supply a merge function. See Styling slots.
Where do I start? Install the engine you need plus one adapter. Example path: @sometic/forms + @sometic/react/form, or @sometic/dom + @sometic/elements.
Are packages independently versioned? Yes, via Changesets. Coordinated bumps happen when cross-package APIs move together. See Releases.