CORE
Styling
There is no styling solution inside AmoJS and none is coming. class and style are attributes like any other, so dynamic ones are just attribute holes; stylesheets are files that amo build copies verbatim; scoping is a platform feature now.
class and style are attributes
A hole must be the whole attribute value, so build the string in a function hole.
html`<div class="${() => (open.value ? 'panel open' : 'panel')}">…</div>`
html`<div style="${() => `--progress: ${pct.value}%`}">…</div>`
html`<button class="${kind}">…</button>` // a signal holding 'primary' | 'ghost'
Plain CSS files
Every non-module file under src/ — css, images, fonts — is copied to the same path in dist/; src/public/ goes to the root. Link the stylesheet from your page or layout. In amo dev a css edit hot-swaps without reloading the page or resetting island state.
Scoping with @scope
CSS @scope (Baseline 2024) scopes a block to a subtree, with an optional lower boundary — what CSS-in-JS and SFC scoped styles used to emulate.
/* src/styles/card.css — copied to dist as-is */
@scope (.card) to (.card-body) {
:scope { border: 1px solid var(--line); border-radius: 6px; }
h2 { margin: 0; font-size: 16px; } /* only h2s between .card and .card-body */
}
Theming
Custom properties on :root, overridden by a data-theme attribute and by prefers-color-scheme. This site does exactly that — the token file is the only place a hex value is allowed.
:root { --brand: #6553E8; --line: #E5E7E1; }
[data-theme="dark"] { --brand: #8B7BFF; --line: #1E2027; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --brand: #8B7BFF; } }
Why nothing is built in
Scoped styles need either a compiler that rewrites selectors or a runtime that generates class names — the first breaks the "touch nothing but templates" rule the compiler lives by, the second costs bytes on a 2 KB budget and cannot be ejected as code you would have written. The platform's answer is good enough, and it is already in every browser.