Where aparté runs
The browsers, Node versions, frameworks, bundlers and TypeScript settings @aparte/* supports — the lowest browser version each feature it uses sets, and what CI runs.
Browsers
Section titled “Browsers”| Engine | Lowest version | What sets it | Run in CI |
|---|---|---|---|
| Chrome, Edge | 111 | color-mix() | Chromium 149 |
| Safari, iOS Safari | 16.2 | color-mix() | WebKit 26.5 |
| Firefox | 121 | :has() | Firefox 151 |
| Samsung Internet | 22 | color-mix() | — |
The lowest version is declared from the features the code uses with no fallback: it is the oldest
in which all of them draw. CI runs only the builds in the last column: every example app in
Chromium, vanilla, vanilla-dist, react, vue and svelte4 in WebKit, and vanilla and react in Firefox, each on
a part of the suites. The JavaScript is ES2022 and is not compiled lower.
color-mix()draws the soft buttons, the alerts and badges, the person’s message bubble and the control borders.:has()draws the focus ring and the checked mark on a choice row, the focus ring on a conversation row, and the invalid border on a field group.
What degrades instead:
- Each accent as text — the active conversation’s mark, a success sign, a button’s text in its accent colour — keeps its accent’s hue at a set lightness with relative colour syntax (Chrome 119, Safari 16.4, Firefox 128); before, it is the accent mixed with the text colour, which still reads at 4.5:1 or more on the default palette, washes included.
- The editor’s padding is worked out from its line height with the
lhunit (Safari 16.4, Firefox 120); before, fromem, to the same pixel. - A filled button’s ink — the text on a solid brand colour — is computed with relative colour
syntax under
@supports; without it, the fixed--aparte-on-intentis used, readable on the default palette except on the neutral fill (3.38:1 in light) (the text on a fill). :dir()places the active conversation’s mark on the right in a right-to-left page; Chrome before 120 keeps it on the left.content-visibilityis a rendering hint, ignored where it is not supported.
On a plain http:// address
Section titled “On a plain http:// address”crypto.randomUUID and navigator.clipboard exist only on https:// and localhost. Core
reaches both through a fallback, uuid() and copyText(), both exported: on a plain http://
address — a model on a machine of your network — the copy buttons use execCommand('copy') and ids
come from a non-cryptographic generator
(the pieces core exports).
Every package declares engines.node >=18, and CI runs Node
18 and 24. In Node, @aparte/core resolves to an entry without elements —
the types, the parsers, AparteClient, the transports and the server handlers — that touches no
DOM at import, so a server render can import it; @aparte/engine has no DOM at all. A test runner
on Node takes the same entry, so under jsdom no element upgrades: alias it to @aparte/core/browser
(Testing your components).
Frameworks
Section titled “Frameworks”| Wrapper | Peer dependencies |
|---|---|
@aparte/react | react and react-dom ^18.0.0 || ^19.0.0 |
@aparte/vue | vue ^3.5.0 |
@aparte/svelte | svelte ^4.0.0 || ^5.0.0 |
@aparte/angular | @angular/core and @angular/common ^19.2.0, rxjs ^7.8.0 |
Each wrapper also takes @aparte/core >=0.21.0 <1.0.0 as a peer: install the two
from the same release. Each wrapper’s example runs in the browser suite — one for Svelte 4 and one
for Svelte 5 — and the React wrapper is typechecked against React 18 as well.
@aparte/plugin-model-selector takes the four frameworks as
optional peers.
Bundlers and TypeScript
Section titled “Bundlers and TypeScript”The packages are ES modules only, with no CommonJS build: a require() of one works only where
Node loads ES modules synchronously — 20.19 and 22.12 onwards — and not on Node 18. Each ships an
exports map, which Vite, webpack 5, Rollup and esbuild follow, and Parcel 2 with
packageExports on. Core’s sideEffects names its CSS and its element entry, so a bundler keeps
those and drops what you do not import; most other packages declare none, and the approval,
ask-user and model-selector plugins are kept whole. In TypeScript, use moduleResolution
bundler, node16 or nodenext, not node. The declarations are emitted with TypeScript
5.7. Without a bundler, the packages load from a CDN
(From a CDN).
At or above a lowest version, a break is a bug: open an issue with the engine and its version. Below it, nothing is run.