Skip to content

Styling

The editor uses CSS custom properties for all visual styling. Override them on :root.

:root {
--updog-grid-cell-bg-idle: #ffffff;
--updog-grid-header-bg-idle: #f8f9fa;
}
  • Override on :root, not a wrapper. Modals, dropdowns, and tooltips render in a portal at the end of the page, so a selector scoped to a wrapper around the editor will not reach them.
  • Load your stylesheet after Updog’s. Both sit at :root, so they share specificity and source order decides the winner.
  • Inspect to find the token. Open devtools on the element you want to change, read the var(--updog-*) in its rule, and override that token. The names map to what you see: surface is background, content is text, border is lines.

Backgrounds, ordered from the flat base up to the most raised panel.

VariableDescription
--updog-surface-layer0Base canvas background
--updog-surface-layer1Raised panel background
--updog-surface-layer2Higher panel and input background
--updog-surface-layer3Nested or hovered surface
--updog-surface-layer4Most raised surface
VariableDescription
--updog-border-primaryDefault border, on nearly every element
--updog-border-secondaryLighter line on dropdowns and a few inner edges

Text colors. primary is the base color the editor inherits everywhere; the others are exceptions you set as needed.

VariableDescription
--updog-content-primaryPrimary text, inherited as the base color
--updog-content-secondaryMuted text
--updog-content-tertiaryFaint text
--updog-content-placeholderPlaceholder and hint text
--updog-content-inverseText on brand-colored surfaces (stays light in dark mode)

Status tags such as row counts and value flags. Each color has a background and a text token.

VariableDescription
--updog-tag-neutral-bg / --updog-tag-neutral-contentNeutral tag
--updog-tag-red-bg / --updog-tag-red-contentRed tag
--updog-tag-yellow-bg / --updog-tag-yellow-contentYellow tag
--updog-tag-green-bg / --updog-tag-green-contentGreen tag
--updog-tag-blue-bg / --updog-tag-blue-contentBlue tag
VariableDescription
--updog-grid-cell-bg-idleDefault cell background
--updog-grid-cell-content-idleDefault cell text color
--updog-grid-cell-border-idleDefault cell border
--updog-grid-cell-bg-hoverHovered cell background
--updog-grid-selection-bgSelected cell background
--updog-grid-focus-ring-borderFocused cell border
--updog-grid-cell-bg-dirtyEdited cell background
--updog-grid-cell-bg-invalidInvalid cell background
--updog-grid-cell-content-cutCut cell text color
--updog-grid-cell-placeholder-idlePlaceholder cell text color
VariableDescription
--updog-grid-header-bg-idleDefault header background
--updog-grid-header-content-idleDefault header text color
--updog-grid-header-bg-activeHighlighted header background
--updog-grid-header-bg-selectedSelected header background
--updog-grid-header-icon-idleHeader icon color
VariableDescription
--updog-grid-marker-bg-idleDefault marker background
--updog-grid-marker-content-idleDefault marker text color
--updog-grid-marker-bg-activeHighlighted marker background
--updog-grid-marker-bg-selectedSelected marker background
--updog-grid-status-bar-bg-newNew row bar color
--updog-grid-status-bar-bg-editedEdited row bar color
--updog-grid-status-bar-bg-errorError row bar color
--updog-grid-status-bar-bg-emptyEmpty row bar color
VariableDescription
--updog-grid-selection-borderSelection range border
--updog-grid-clipboard-border-copyClipboard marquee border (copy)
--updog-grid-clipboard-border-cutClipboard marquee border (cut)
VariableDescription
--updog-grid-fill-overlay-bgFill overlay background
--updog-grid-fill-overlay-borderFill overlay border
--updog-grid-fill-handle-bgFill handle background
--updog-grid-fill-handle-borderFill handle stroke
VariableDescription
--updog-grid-match-bg-defaultDefault match background
--updog-grid-match-bg-currentCurrent match background
VariableDescription
--updog-grid-tooltip-bg-errorError tooltip background
--updog-grid-tooltip-bg-warningWarning and dirty tooltip background
VariableDescription
--updog-grid-skeleton-bgSkeleton background
--updog-grid-skeleton-highlightSkeleton shimmer

Updog ships no dark theme. Build one by re-declaring variables under your own dark selector. The canvas grid repaints automatically when the theme changes.

Work with the ramps rather than the semantic tokens:

  1. Point --updog-ramp-light at your dark base. surface-layer0 and every low shade you do not tune lean toward it, so nothing strays light. Leave --updog-ramp-dark black.
  2. Set the gray ramp. Surfaces, borders, content, disabled, and the neutral tag all derive from gray shades, so tuning the ramp flips them together. The high grays carry text and must be light; the low grays are tuned for surface depth, since a linear mix lacks separation in the dark band.
  3. Invert the colored ramps. Point each 50 and 100 shade at its dark counterpart (--updog-brand-50: var(--updog-brand-950)), which flips button hovers, tag and tooltip backgrounds, selection, edited and invalid cells, matches, and skeletons.
  4. Keep the row status bars saturated so the strip stays visible.
.dark {
/* Dark base: surface-layer0 and every untuned low shade lean toward this, so
nothing strays light. Leave ramp-dark black so the -950 shades the colored
ramps invert toward stay dark. */
--updog-ramp-light: #0f1115;
/* Gray ramp. Surfaces, borders, content, disabled, and the neutral tag all
derive from these. The high grays carry text, so they must be light; the
low grays are tuned for surface depth. */
--updog-gray-50: #161a20;
--updog-gray-100: #1e232b;
--updog-gray-200: #262c36;
--updog-gray-300: #2f3641;
--updog-gray-400: #5c6370;
--updog-gray-450: #5c6370;
--updog-gray-500: #6b7280;
--updog-gray-600: #a8aeb8;
--updog-gray-950: #e6e8eb;
/* Colored ramps invert: subtle fills go dark, accents and text stay bright */
--updog-brand-25: var(--updog-brand-950);
--updog-brand-50: var(--updog-brand-950);
--updog-brand-100: var(--updog-brand-900);
--updog-red-50: var(--updog-red-950);
--updog-red-100: var(--updog-red-900);
--updog-yellow-50: var(--updog-yellow-950);
--updog-yellow-100: var(--updog-yellow-900);
--updog-green-50: var(--updog-green-950);
--updog-green-100: var(--updog-green-900);
--updog-blue-50: var(--updog-blue-950);
--updog-blue-100: var(--updog-blue-900);
/* Keep the row status bars saturated so the strip stays visible */
--updog-grid-status-bar-bg-new: var(--updog-green-700);
--updog-grid-status-bar-bg-edited: var(--updog-yellow-700);
--updog-grid-status-bar-bg-error: var(--updog-red-700);
--updog-grid-status-bar-bg-empty: var(--updog-gray-700);
}

Changing a base color such as --updog-brand does not produce dark mode. The generated shades always run light to dark in the same direction, so a base swap only tints. Inverting the light shades is what turns the polarity around.

A few more things:

  • Apply your dark selector high in the page, above the editor and the portal root, not on a wrapper around the editor, so it reaches the portaled modals and dropdowns. The canvas grid repaints on the change.
  • Keep --updog-content-inverse light. It is the text on brand-colored buttons, so it should stay light in dark mode.