main menu

Theming & customization

The components are designed to be styled from the host page using CSS custom properties. There are no Sass overrides or build steps — set a variable in :root (or any ancestor) and the value flows through Shadow DOM to every component on the page.

How customization works

Every component lives in a Shadow DOM, but CSS custom properties pierce that boundary. Set a token at the root of your page and the components see it:

:root {
  --accent: #ff6f00;          /* changes link / focus / hover accent everywhere */
  --medium-font: 18px;        /* shrinks the base font size globally */
}

You can also scope an override to a region of the page (e.g. only the sidebar) by setting the variable on a specific ancestor:

aside.sidebar {
  --menu-active-bg: #fff5e6;  /* only the menu inside this aside picks up the override */
}

Where a component-specific knob exists (--menu-*, --query-*, --include-*), it takes precedence over the global token it's based on, so you can retheme one component without touching others.

Light & dark themes

Light is the default. Add data-theme="dark" to the <html> element (or any ancestor of your components) to switch to the bundled dark palette:

<html data-theme="dark">
  ...
</html>

The dark theme reassigns these tokens — every component that respects them flips automatically:

TokenLight defaultDark override
--bg #f5f5f5#1a1a1a
--surface #ffffff#252525
--border #d0d0d0#3e3e3e
--text #000000#e0e0e0
--text-muted #4d4d4d#909090
--hover #eaf2fb#2e2e2e
--focus-bg #ebf5fb#2a2e34
--code-bg #f4f4f4#1e1e1e
--accent #1F618D#4dabf7
--accent-dark #2980b9#339af0

To follow the system preference automatically:

<script>
  if (matchMedia('(prefers-color-scheme: dark)').matches) {
    document.documentElement.dataset.theme = 'dark';
  }
</script>

To define your own theme, override any subset of tokens — you don't have to redefine the whole palette:

:root[data-theme="brand"] {
  --accent:      #ff6f00;
  --accent-dark: #c44a00;
  --hover:       #fff3e0;
  --focus-bg:    #ffe0b2;
}

Colors & surfaces

VariableDefault (light)What it controls
--bg #f5f5f5Page background (intended for the host page; components mostly use --surface)
--surface #ffffff Component surface fill — popups, modals, cards, table cells
--border #d0d0d0Lines and dividers
--text #000000 Primary text color
--text-muted #4d4d4dSecondary text — captions, field labels
--accent #1F618DBrand color — links, active states, focus rings
--accent-dark#2980b9Hovered/pressed accent
--hover #eaf2fbBackground tint on hover
--focus-bg #ebf5fbBackground tint on the focused/active item
--code-bg #f4f4f4Background for <code> and <pre>
--error #e74c3cError message color and outline
--success #27ae60Success state (reserved — currently unused)

Typography

Three sizes (small/medium/large) plus a separate --font-size alias for "the default body size." Medium is the default. Nothing in any component renders below 16 px.

VariableDefaultWhat it controls
--small-font 16pxCompact text — field labels, sort markers, button text in tight contexts, badges
--medium-font 20pxDefault body / control / table size
--large-font 24pxSection headers (e.g. sol-query subject banner)
--font-size var(--medium-font, 20px)Alias the components reach for first; override to retag the default size
--font-ui 'Segoe UI', Roboto, sans-serifUI font family
--font-mono 'Cascadia Code', 'Fira Code', 'Consolas', monospaceMonospace family for code blocks and Turtle output
--font-weight-normal400Body weight
--font-weight-bold 600Bold weight (table headers, active items, field labels)
--line-height-tight 1.25Headings
--line-height-base 1.5Body text
To make everything smaller (or bigger) globally: override --medium-font (or --font-size). Components that explicitly use --small-font or --large-font for emphasis stay at their tier — small stays smaller than medium even after you change medium.

Spacing & radius

VariableDefaultUsed for
--space-xs 2px Tight gaps (popup item gap, nav item gap)
--space-sm 4px Small gaps (small text margin)
--space-md 8px Default padding for nav items, table cells
--space-lg 12pxLarger paddings (subject-nav, error/loading)
--space-xl 16pxContent paddings, single-value cells
--space-2xl 24pxModal padding, section breaks
--radius-sm 4px Buttons, error boxes, links
--radius-md 6px Popups, modals

Shadows & scrim

VariableDefaultWhere
--shadow rgba(0,0,0,0.08)Generic surface drop shadow (cards)
--shadow-popup 0 4px 12px rgba(0,0,0,0.12)Submenu popup elevation
--shadow-modal 0 8px 24px rgba(0,0,0,0.25)Modal dialog elevation
--scrim rgba(0,0,0,0.4)Backdrop dim behind modals

Override these to retheme just the menu without touching anything else.

VariableDefaultWhat it controls
--menu-nav-min-width 140pxSidebar nav minimum width
--menu-nav-max-width 260pxSidebar nav maximum width
--menu-popup-min-width 160pxSubmenu popup minimum width
--menu-button-padding var(--space-md) var(--space-lg)Menu item padding (shorthand: vertical horizontal)
--menu-button-radius var(--radius-sm, 4px)Menu item corner radius
--menu-hover-bg var(--hover, #f0f0f0)Background on hover
--menu-hover-color var(--accent-dark, #1976d2)Text color on hover
--menu-active-bg var(--focus-bg, #e3f2fd)Background of the current item
--menu-active-color var(--accent-dark, #1976d2)Text color of the current item

sol-query knobs

VariableDefaultWhat it controls
--query-th-bg var(--accent-dark, #2C3E51)Table header background
--query-th-color #fffTable header text
--query-row-alt-bg var(--hover, #fafafa)Zebra-stripe color for even rows
--query-cell-padding var(--space-md) var(--space-lg)Cell padding (vertical horizontal)
--query-link-color var(--accent, #0066cc)Cell link color
--query-bnode-link-color var(--text-muted, #777)Color of "[…]" blank-node placeholder links
--bnode-modal-max-width min(90vw, 700px)Width cap for the blank-node properties modal
--bnode-modal-max-height 80vhHeight cap for the blank-node properties modal

sol-include knobs

VariableDefaultWhat it controls
--include-code-bg var(--code-bg, #f0f0f0)Background of inline <code> and <pre> blocks
--include-code-padding .1em .3emPadding around inline code
--include-pre-padding var(--space-lg, 12px)Padding inside <pre> blocks
--include-blockquote-bordervar(--border, #ccc)Left border color of blockquotes
--include-blockquote-color var(--text-muted, #555)Blockquote text color

Shadow parts & slots

For things that can't be themed via variables alone, components expose part="…" hooks (style from the host page with ::part(name)) and <slot>s (insert your own HTML into a known position, then style it with ::slotted()). The deliberate stance is to keep this surface small — exposing a part or slot is a public-API commitment that's slower to evolve than CSS variables.

Parts

ComponentPartWhat it is
sol-modaltriggerThe button that opens the modal. Default styling is the standard .sol-btn.
sol-modal::part(trigger) {
  background: #ff6f00;
  color: #fff;
  border-radius: 999px;
  padding: 8px 16px;
}

Slots

ComponentSlotFallbackWhat it is
sol-modal (default) literal text Open Inside the trigger button. Put your own label or icon between <sol-modal> tags to override the default text.
<sol-modal title="Edit settings">
  <span>⚙ Settings</span>       <!-- replaces the "Open" fallback -->
</sol-modal>

<style>
  /* ::slotted() reaches the host-page node we passed in */
  sol-modal::part(trigger) ::slotted(span) { letter-spacing: .05em; }
</style>

I want to restyle X — what do I use?

Most surfaces ship as CSS variables rather than parts. Quick reference for the things authors most often want to retheme:

To restyle…Reach for…
Brand color anywhere --accent + --accent-dark
The modal's open button sol-modal::part(trigger)
The modal's open-button label Default <slot> in <sol-modal>
The modal's body, close button, scrim --surface, --shadow-modal, --scrim (no parts yet)
sol-menu sidebar / popup --menu-* variables (see sol-menu knobs)
sol-query table headers / cells --query-* variables (see sol-query knobs)
sol-query view container Style the host element directly: sol-query { … } — nothing inside the shadow root reaches it
sol-include rendered content --include-* variables; nested HTML appears in the host's light DOM, so normal CSS selectors apply.
sol-login button text / icon No part yet — host-page CSS targeting sol-login can adjust its outer box; for inner button restyle, override --accent/--surface.
Loading / error states across components--text-muted (loading), --error (errors)
Per-region override (only one section) Set the variable on an ancestor element, not :root — see How customization works.

Recipes

Brand-color override (one line, affects everything)

:root {
  --accent:      #ff6f00;
  --accent-dark: #c44a00;
}

Compact mode (smaller body type, tighter spacing)

:root {
  --medium-font: 16px;
  --small-font:  14px;   /* OK to drop below 16px if you accept the WCAG tradeoff */
  --space-md:    6px;
  --space-lg:    8px;
}

Theme just the menu, leave query and include alone

:root {
  --menu-active-bg:    #fff3e0;
  --menu-active-color: #c44a00;
  --menu-hover-bg:     #fff8e1;
}

Replace zebra-striping with a flat table

:root {
  --query-row-alt-bg: var(--surface);   /* makes even rows match odd rows */
}

Auto dark mode (follow OS preference)

<script>
  const root = document.documentElement;
  const apply = e => root.dataset.theme = e.matches ? 'dark' : 'light';
  const mql = matchMedia('(prefers-color-scheme: dark)');
  apply(mql); mql.addEventListener('change', apply);
</script>

Three custom themes the user can switch between

:root[data-theme="ocean"]  { --accent: #0277bd; --accent-dark: #01579b; --hover: #e1f5fe; }
:root[data-theme="forest"] { --accent: #2e7d32; --accent-dark: #1b5e20; --hover: #e8f5e9; }
:root[data-theme="sunset"] { --accent: #e64a19; --accent-dark: #bf360c; --hover: #fff3e0; }
// JS to switch
document.documentElement.dataset.theme = 'forest';