Swarmz

Raw CSS

Write real stylesheets against the DOM, sanitized and scoped to your surfaces

The raw CSS tier is the escape hatch for teams whose design needs go past the rules channel: a real stylesheet, written by your dev team, targeting the app's actual DOM — its data-part and data-slot attributes, semantic elements, and classes.

It's admin-enabled: your account needs the raw_css_enabled capability, switched on by Swarmz on request. Once enabled, the Branding studio's CSS/Code mode shows the raw CSS panel with the same draft → preview → publish lifecycle as rules. Turning raw CSS off (clearing the live stylesheet) always works, gated or not.

What you're targeting

The white-label surfaces carry stable styling hooks:

  • [data-part="Button"] — component identity, the same part names as the parts catalog
  • [data-slot="sidebar"] — named regions within a part (see the slot inventory)
  • [data-state="open"] — dynamic state, plus bespoke attributes like data-active on nav items
/* real CSS, real selectors */
[data-part="SidebarRoot"] {
  border-right: 1px solid var(--line-strong);
  backdrop-filter: blur(12px);
}

[data-part="ProjectCard"]:hover {
  transform: translateY(-2px);
  transition: transform 120ms ease;
}

@media (min-width: 1024px) {
  [data-slot="logo"] {
    padding-block: 1.25rem;
  }
}

Unlike the rules channel you get the full property surface — transforms, filters, grid, custom fonts via @font-face, animations via @keyframes. The trade-off: raw CSS couples you to DOM details that aren't a versioned contract. Prefer data-part / data-slot hooks over utility class names, which can change without notice.

The sanitizer

Every byte you submit is parsed and rewritten server-side before it's stored; only the sanitized output is ever served. The policy:

Scoping — your CSS can only touch your surfaces. Every selector is force-prefixed with html[data-whu], the attribute present only on white-label customer sessions. html-anchored selectors are rewritten (html.foohtml[data-whu].foo), :root becomes html[data-whu], and any selector that can't be confidently scoped is stripped rather than let through. Admin, editor-internal, and non-white-label chrome are out of reach by construction.

Allowed at-rules: @media, @supports, @font-face, and @keyframes (including vendor-prefixed). Everything else — @import, @charset, @namespace, @layer, @container, @scope, @page — is stripped. CSS nesting (a style rule inside a style rule) is stripped too; write flat selectors.

Stripped declarations: anything containing expression(, -moz-binding, or behavior:, and any url() (or string-URL argument to image-set() / cross-fade()) whose scheme isn't explicitly https: or data:. Protocol-relative and relative URLs are rejected — fail closed. Escape-sequence obfuscation is decoded before screening.

Size cap: 200 KiB after sanitizing (submission bodies cap at 400 KB).

Everything stripped is reported back line-by-line when you save a draft, so you can see exactly what the sanitizer took out and why.

Lifecycle

  1. Draft — submit CSS; it's sanitized and stored as an immutable draft with a content hash. The 20 newest drafts are kept per account.
  2. Preview — load the draft in the studio preview before anything ships.
  3. Publish — confirm the exact hash you previewed. Publishing echoes the hash back as a confirmation (confirm must equal the hash), so a stale tab can't ship a stylesheet you never saw. Clearing uses { "hash": null, "confirm": "clear" }.

Published raw CSS is delivered from the same immutable /t/ artifact route as compiled rules, and each publish is recorded in the version history.

Cascade order

Raw CSS applies on top of your tokens and rules-channel styles. Use it for what the rules channel can't express, and keep color decisions on tokens (var(--brand) and friends) so the palette stays editable in one place.

On this page