MallaDocs

Style compiler

The style storage format, cascade layers, breakpoints and how CSS is compiled.

Developer guide

User styles are plain CSS stored as data and compiled by @malla/renderer. Panda CSS styles only the editor itself; it cannot see user styles, which live in the database.

Storage format

Breakpoint-first, camelCase property names, string values with units. Keys are <breakpoint> or <breakpoint>:<state>; components add variant:<name>.

json
"styles": {
  "base":       { "display": "flex", "gap": "12px", "color": "var(--color-brand)" },
  "base:hover": { "opacity": "0.9" },
  "tablet":     { "paddingBlock": "80px" },
  "mobile":     { "flexDirection": "column" }
}
  • Each key compiles to exactly one rule or media block, and the panel reads and writes styles[breakpoint] directly.
  • “Overridden on tablet” means the property exists in styles.tablet; deleting the key resets it. Empty objects are removed.
  • Tokens are CSS variables: --color-*, --font-*, --space-*.
  • Bound values live apart in styleBindings and compile to per-element CSS variables set at run time.

Cascade

Cascade layers, low to high
@layer reset
@layer tokens
@layer classes
@layer nodes
css
@layer reset, tokens, classes, nodes;

@layer classes {
  .btn { padding: 12px 20px; background: var(--color-brand); }
  .btn:hover { opacity: .9; }
  .btn.btn-ghost { background: transparent; }
}
@layer nodes {
  .n-hero { padding-block: 120px; }
  @media (max-width: 767px) { .n-hero { padding-block: 64px; } }
}

Precedence never depends on specificity accidents: class → combo class → node. Combo classes compile to compound selectors because CSS ignores the order of names in the class attribute. Breakpoints are desktop-first (max-width: 991 px tablet, 767 px mobile), emitted in order inside each layer.

html
<section class="hero n-hero" data-node="hero">…</section>

In the editor

  • Each canvas frame gets separate style layers; editing a node recompiles only that node’s rule, so slider drags never re-parse the page CSS.
  • Viewport units are rewritten to calc(n * var(--malla-vh)) in the editor so content-sized frames never grow forever; published CSS keeps real units.

At publish

Shared CSS (tokens, reset, classes) is compiled once per snapshot with content-hashed names; unused classes are dropped; output is minified.