Theming¶
kaboo-react ships a single stylesheet and styles everything with CSS variables, so it blends into your app's design system and is easy to override.
How styling works¶
Components read standard design-system tokens with neutral fallbacks:
--background,--foreground--card--muted,--muted-foreground--border
If your app already defines these (as most design systems / shadcn setups do), kaboo-react inherits them automatically. Otherwise it falls back to sensible neutral defaults.
Import the stylesheet¶
Import it once, near your app root:
import "@pgege/kaboo-react/styles.css";
The package sets "sideEffects": ["*.css"], so bundlers keep the stylesheet even
with tree-shaking enabled.
Override tokens¶
Status colors and other accents are exposed as --kaboo-* variables. Set them on
any parent element (e.g. :root) to override:
:root {
--kaboo-running: #d97706;
--kaboo-warning: #f59e0b;
--kaboo-success: #16a34a;
}
Dark mode¶
Because components read --background / --foreground / --card etc., dark mode
works by toggling those tokens the same way you do for the rest of your app (for
example, a .dark class on <html> that redefines the variables). No
kaboo-specific dark-mode configuration is required.
Questions and approvals¶
The question card, the approval card, the batch bar and the permission list use
the same tokens (--kaboo-card, --kaboo-border, --kaboo-muted,
--kaboo-success, --kaboo-success-bg, --kaboo-accent, --kaboo-warning)
and a stable set of class names, so you restyle them instead of rebuilding them.
These names are part of the public surface and change only with an entry in the
upgrade guide.
| Element | Class |
|---|---|
| Any request card | kaboo-interrupt (with kaboo-interrupt-approval, kaboo-interrupt-form or kaboo-interrupt-custom) |
| Card heading | kaboo-interrupt-header, kaboo-interrupt-message |
| Buttons | kaboo-interrupt-btn, plus -approve, -reject, -next, -back, -skip |
| Question text, steps | kaboo-interrupt-question, kaboo-interrupt-progress |
| Options | kaboo-interrupt-choices, kaboo-interrupt-option, kaboo-interrupt-option-selected |
| The Other row | kaboo-interrupt-option-other, kaboo-interrupt-other-input |
| What a wider approval covers ("Applies to …"), input | kaboo-approval-covers, kaboo-interrupt-details, kaboo-interrupt-pre |
| Approval buttons | kaboo-approval-actions, kaboo-approval-scope (-thread, -always), kaboo-approval-dismiss |
| Deny with a reason | kaboo-approval-deny, kaboo-approval-reason |
| Deadline | kaboo-approval-expiry, kaboo-approval-expired |
| Approve all / Deny all | kaboo-approval-batch, kaboo-approval-batch-count |
| Answered | kaboo-interrupt-responded |
| Remembered permissions | kaboo-permissions, kaboo-permission, kaboo-permission-label, kaboo-permission-scope, kaboo-permission-revoke |
For example, pill-shaped options and a brand-coloured selection:
.kaboo-interrupt-option {
border-radius: 999px;
}
.kaboo-interrupt-option-selected,
.kaboo-interrupt-btn-approve {
border-color: var(--primary);
background: color-mix(in srgb, var(--primary) 12%, transparent);
color: var(--primary);
}
Replace a card entirely with interruptRenderers only when its structure must
change — see Human-in-the-loop.