heedbackdocs

Portal appearance & custom CSS

Make your feedback portal and widgets look like part of your own product. Two layers: theme tokens for the common cases (colours, corner radius, font) and custom CSS for everything else. Both are on the Team plan, under Settings → Portal appearance.

Theme tokens

The token form is the supported, stable way to re-colour the portal and the embedded feedback / changelog widgets. Set any of these and leave the rest blank:

TokenWhat it controls
Accent / primaryButtons, links, vote controls, focus rings
Text on accentText sitting on a primary-coloured button
Page backgroundThe portal surface / widget panel background
Body textDefault text colour
Muted textSecondary text (timestamps, counts)
BordersCard and input borders
LinksPortal link colour
Corner radiusRoundness of cards, buttons and inputs (0–24 px)
FontOne of eight system-safe font stacks

Under the hood each token sets a CSS variable that the portal's own components already read (--primary, --radius, --border, …). Your custom CSS can read them back as var(--hb-primary), var(--hb-radius), and so on.

Custom CSS

Open Advanced → Custom CSS for full control. What you write is sanitised on save and injected into the portal after our own stylesheet, so your rules win on ties.

The stable contract

These hooks are documented and versioned — we announce before changing them:

  • [data-hb-portal] — wraps the whole portal. Every rule you write is automatically confined inside it.
  • .hb-embed-root — the feedback and changelog widget roots. Widget CSS is confined here.
  • Component classes: .hb-portal-header, .hb-portal-nav, .hb-post-list, .hb-post-card, .hb-vote-button, .hb-changelog-entry, .hb-roadmap-column.
  • The --hb-* variables listed above.

Anything else — Tailwind utility classes, internal element IDs, DOM structure — is internal and may change without notice. Target it at your own risk.

We keep the documented classes and variables stable and announce changes, but we can't support how your CSS renders. Use Preview before you publish.

Starter snippet

[data-hb-portal] {
  --hb-primary: #6c47ff;
  --hb-radius: 4px;
}

[data-hb-portal] .hb-post-card {
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

.hb-embed-root .hb-post-card {
  font-size: 14px;
}

What's not allowed

The sanitiser strips (and tells you what it removed): @import, @property, @layer, off-site url(...) and image-set(...), attr() in any property, expression(), javascript: URLs, and — in the widgets only — position: fixed / sticky anywhere, plus z-index and sizing on the widget root itself (these could cover the host page). SVG and non-woff2 data: URLs are rejected. Max 64 KB.

@media (width < 600px) range syntax does not survive sanitising — use @media (max-width: 600px) instead. url() must appear directly in a property, not inside a CSS custom property or a var() fallback (--x: url(...) is dropped). Nested rules (& .child { }) aren't supported — write the full selector.

Draft, preview, publish

  • Save draft stores your changes without touching the live portal.
  • Save & preview opens your real portal in a new tab with the draft applied (a private, 5-minute link).
  • Publish makes the draft live for everyone.

Version history

Every publish is snapshotted. Version history under the editor lists the last 20, with a Restore on each. Restoring makes that version the live CSS and your current draft — and it's snapshotted too, so a restore can be undone. Restored CSS is re-checked against the current rules, so anything no longer allowed is stripped on the way back in.

Turning it off

  • The Apply custom appearance switch stops applying your tokens and CSS without deleting them. This always works, even if your plan lapses.
  • Add ?heedback-css=off to any portal URL to view it with no custom appearance for that one page load — useful for checking whether a display problem is your CSS or ours.