Theme Customization =================== Buckaroo tables automatically match your OS light/dark preference. But sometimes you want more control — a branded dashboard, a high-contrast accessibility mode, or just a color scheme you enjoy staring at for hours. The ``component_config.theme`` dictionary gives you full control over the color scheme without touching CSS. Every example on this page is a live static embed — no server, no kernel, just HTML and JavaScript. Quick start ----------- .. code-block:: python import buckaroo # Jupyter / IPython — just set component_config on the widget w = buckaroo.BuckarooWidget(df, component_config={ 'theme': { 'colorScheme': 'dark', 'accentColor': '#00bcd4', } }) # Static embed — inject theme into the artifact from buckaroo.artifact import prepare_buckaroo_artifact, artifact_to_json artifact = prepare_buckaroo_artifact(df) artifact['df_viewer_config'].setdefault('component_config', {})['theme'] = { 'colorScheme': 'dark', 'accentColor': '#00bcd4', } # MCP server — pass component_config in the /load request body {"session": "my-session", "path": "data.csv", "component_config": { "theme": {"colorScheme": "dark", "accentColor": "#00bcd4"} }} ThemeConfig reference --------------------- All properties are optional. Omitted properties use sensible defaults based on the resolved color scheme. Color properties ~~~~~~~~~~~~~~~~ .. list-table:: :header-rows: 1 :widths: 22 14 50 * - Property - Type - Description * - ``colorScheme`` - ``'light'`` | ``'dark'`` | ``'auto'`` - Override OS color scheme detection. ``'auto'`` (the default) respects the user's system preference. * - ``accentColor`` - CSS color - Primary highlight color for column selection, active tabs, and buttons. Default: ``#2196F3`` (blue). * - ``accentHoverColor`` - CSS color - Hover state for accent elements. Should be a darker shade of ``accentColor``. * - ``backgroundColor`` - CSS color - Main table background. Default: ``#ffffff`` (light) or ``#181D1F`` (dark). * - ``foregroundColor`` - CSS color - Text and icon color. Passed through to AG Grid's theme system. * - ``oddRowBackgroundColor`` - CSS color - Alternating row stripe color. Default: ``#f5f5f5`` (light) or ``#222628`` (dark). * - ``borderColor`` - CSS color - Grid line and border color. Passed through to AG Grid's theme system. * - ``headerBorderColor`` - CSS color - Border color between column headers. Controls the vertical dividers between columns in the header row — including MultiIndex group headers. * - ``headerBackgroundColor`` - CSS color - Background color for all header rows. With MultiIndex columns, this colors both the group header row and the leaf header row. Layout properties ~~~~~~~~~~~~~~~~~ .. list-table:: :header-rows: 1 :widths: 28 10 48 * - Property - Type - Description * - ``spacing`` - number - Base spacing unit in pixels. Controls the overall density of the grid. Default: ``5``. Lower values = more compact. * - ``cellHorizontalPaddingScale`` - number - Multiplier for horizontal cell padding. Default: ``0.3``. Use ``0.1`` for very tight or ``1.0`` for spacious. * - ``rowVerticalPaddingScale`` - number - Multiplier for vertical row padding. Default: ``0.5``. Use ``0.2`` for compact or ``1.2`` for airy. Auto light/dark with ``light`` and ``dark`` sub-dicts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When ``colorScheme`` is ``'auto'``, the table follows the OS preference. But a single set of colors can't look good in both modes. Use ``light`` and ``dark`` sub-dicts to define separate palettes: .. code-block:: python component_config = {'theme': { 'colorScheme': 'auto', 'light': { 'accentColor': '#e65100', 'backgroundColor': '#fff8f0', 'foregroundColor': '#3e2723', 'oddRowBackgroundColor': '#fff3e0', 'borderColor': '#ffe0b2', }, 'dark': { 'accentColor': '#ffab40', 'backgroundColor': '#1a1209', 'foregroundColor': '#ffe0b2', 'oddRowBackgroundColor': '#2a1e0f', 'borderColor': '#4e342e', }, }} The resolution order is: **scheme-specific override > top-level color > built-in default**. This means you can set shared properties at the top level and override only what differs per scheme: .. code-block:: python component_config = {'theme': { 'colorScheme': 'auto', 'spacing': 8, # shared — same in light and dark 'headerBorderColor': '#7c4dff', # shared 'light': { 'accentColor': '#7c4dff', 'backgroundColor': '#faf8ff', }, 'dark': { 'accentColor': '#b388ff', 'backgroundColor': '#1a1028', }, }} Both ``light`` and ``dark`` accept all color and layout properties from ``ThemeColorConfig``. CSS custom properties ~~~~~~~~~~~~~~~~~~~~~ Theme properties are injected as CSS custom properties on the wrapper ``div``, so they cascade into all child components: - ``--bk-accent-color`` — accent color - ``--bk-accent-hover-color`` — accent hover color - ``--bk-bg-color`` — background color (always set, with scheme-based fallback) - ``--bk-fg-color`` — foreground color Theme gallery ------------- Each table below renders the same 10-row cities dataset with a different theme configuration. Click a column to see the accent color in action. Default (Light) ~~~~~~~~~~~~~~~ No theme overrides. Uses the OS-detected color scheme with built-in defaults. .. code-block:: python component_config = {} # no theme key needed .. raw:: html Default (Dark) ~~~~~~~~~~~~~~ Force dark mode with just ``colorScheme``. All other colors use the built-in dark defaults — no need to specify ``backgroundColor`` or ``oddRowBackgroundColor``. .. code-block:: python component_config = {'theme': { 'colorScheme': 'dark', }} .. raw:: html .. Custom Accent Color ~~~~~~~~~~~~~~~~~~~ Override just the accent color. Everything else stays default. This is the most common customization — match your brand without changing the overall look. .. code-block:: python component_config = {'theme': { 'accentColor': '#ff6600', # orange — click a column to see it 'accentHoverColor': '#cc5200', # darker orange — command UI buttons }} .. raw:: html Ocean Dark ~~~~~~~~~~ A deep ocean-inspired dark theme with cyan accents. Good for dashboards with a calm, professional feel. .. code-block:: python component_config = {'theme': { 'colorScheme': 'dark', 'accentColor': '#00bcd4', 'accentHoverColor': '#0097a7', 'backgroundColor': '#0a1628', 'foregroundColor': '#b0bec5', 'oddRowBackgroundColor': '#0d2137', 'borderColor': '#1a3a5c', }} .. raw:: html Warm Light ~~~~~~~~~~ A warm, earthy light theme with orange accents. Works well for data presentations where the default blue feels too clinical. .. code-block:: python component_config = {'theme': { 'colorScheme': 'light', 'accentColor': '#e65100', 'accentHoverColor': '#bf360c', 'backgroundColor': '#fff8f0', 'foregroundColor': '#3e2723', 'oddRowBackgroundColor': '#fff3e0', 'borderColor': '#ffe0b2', }} .. raw:: html Neon Dark ~~~~~~~~~ A cyberpunk-inspired dark theme with hot pink accents. The same colors used in the Storybook ``FullCustom`` story. .. code-block:: python component_config = {'theme': { 'colorScheme': 'dark', 'accentColor': '#e91e63', 'accentHoverColor': '#c2185b', 'backgroundColor': '#1a1a2e', 'foregroundColor': '#e0e0e0', 'oddRowBackgroundColor': '#16213e', 'borderColor': '#0f3460', }} .. raw:: html Forest Dark ~~~~~~~~~~~ A dark theme with forest green accents — easy on the eyes for long data exploration sessions. .. code-block:: python component_config = {'theme': { 'colorScheme': 'dark', 'accentColor': '#66bb6a', 'accentHoverColor': '#43a047', 'backgroundColor': '#1b2a1b', 'foregroundColor': '#c8e6c9', 'oddRowBackgroundColor': '#223322', 'borderColor': '#2e7d32', }} .. raw:: html Minimal Light ~~~~~~~~~~~~~ A neutral, low-contrast light theme that keeps data front and center. Uses only grays — no color distractions. .. code-block:: python component_config = {'theme': { 'colorScheme': 'light', 'accentColor': '#9e9e9e', 'accentHoverColor': '#757575', 'backgroundColor': '#ffffff', 'foregroundColor': '#212121', 'oddRowBackgroundColor': '#fafafa', 'borderColor': '#e0e0e0', }} .. raw:: html High Contrast ~~~~~~~~~~~~~ Maximum contrast for accessibility. Bright yellow accents on pure black, with white text and borders. .. code-block:: python component_config = {'theme': { 'colorScheme': 'dark', 'accentColor': '#ffff00', 'accentHoverColor': '#ffd600', 'backgroundColor': '#000000', 'foregroundColor': '#ffffff', 'oddRowBackgroundColor': '#1a1a1a', 'borderColor': '#ffffff', }} .. raw:: html Auto Light/Dark (Branded) ~~~~~~~~~~~~~~~~~~~~~~~~~ Follows the OS preference with separate branded palettes for each scheme. Toggle your OS between light and dark mode to see it switch. .. code-block:: python component_config = {'theme': { 'colorScheme': 'auto', 'light': { 'accentColor': '#e65100', 'accentHoverColor': '#bf360c', 'backgroundColor': '#fff8f0', 'foregroundColor': '#3e2723', 'oddRowBackgroundColor': '#fff3e0', 'borderColor': '#ffe0b2', }, 'dark': { 'accentColor': '#ffab40', 'accentHoverColor': '#ff9100', 'backgroundColor': '#1a1209', 'foregroundColor': '#ffe0b2', 'oddRowBackgroundColor': '#2a1e0f', 'borderColor': '#4e342e', }, }} .. raw:: html Spacious Layout ~~~~~~~~~~~~~~~ Increased spacing, padding, and a purple header border. Good for presentations and read-only dashboards where data density isn't critical. .. code-block:: python component_config = {'theme': { 'colorScheme': 'dark', 'accentColor': '#7c4dff', 'accentHoverColor': '#651fff', 'spacing': 10, 'rowVerticalPaddingScale': 1.2, 'cellHorizontalPaddingScale': 0.8, 'headerBorderColor': '#7c4dff', }} .. raw:: html Compact Layout ~~~~~~~~~~~~~~ Minimal spacing for maximum data density. Fits more rows on screen — good for power users who want to see as much data as possible. .. code-block:: python component_config = {'theme': { 'colorScheme': 'light', 'spacing': 2, 'rowVerticalPaddingScale': 0.2, 'cellHorizontalPaddingScale': 0.15, 'headerBorderColor': '#bdbdbd', }} .. raw:: html VC Pricing Page ~~~~~~~~~~~~~~~ Buckaroo's default styling is what I call **trader styling** — jam information into every pixel, minimize whitespace, maximize data density. This is the opposite: **VC styling**. Generous padding, pastel accents, and three columns where the last one says "Call us for pricing". .. code-block:: python # The data df = pd.DataFrame({ 'Feature': ['Seats', 'Storage', 'API calls/mo', 'SSO', 'Audit log', 'Support'], 'Starter': ['5', '10 GB', '1,000', 'No', 'No', 'Email'], 'Enterprise': ['Unlimited', 'Unlimited', 'Unlimited', 'Yes', 'Yes', 'Call us for pricing'], }) # The theme component_config = {'theme': { 'colorScheme': 'light', 'accentColor': '#6c5ce7', 'accentHoverColor': '#5a4bd1', 'backgroundColor': '#ffffff', 'foregroundColor': '#2d3436', 'oddRowBackgroundColor': '#f8f9ff', 'borderColor': '#e8e8f0', 'headerBorderColor': '#6c5ce7', 'spacing': 16, 'rowVerticalPaddingScale': 2.0, 'cellHorizontalPaddingScale': 1.5, }} .. raw:: html MultiIndex Headers ~~~~~~~~~~~~~~~~~~ MultiIndex (hierarchical) column headers are common after ``pivot_table()`` and ``groupby().agg()``. Three theme properties target the header area: - ``borderColor`` — controls all grid borders, including the thick separator below the header and the vertical dividers between MultiIndex group cells - ``headerBorderColor`` — targets only the vertical dividers between column headers (overrides ``borderColor`` for header cells) - ``headerBackgroundColor`` — colors all header rows, making the group hierarchy visually distinct from the data area .. code-block:: python # The data — what pivot_table() produces cols = pd.MultiIndex.from_tuples([ ('Revenue', 'Q1'), ('Revenue', 'Q2'), ('Revenue', 'Q3'), ('Headcount', 'Engineering'), ('Headcount', 'Sales'), ('Headcount', 'Support'), ], names=['Category', 'Detail']) df = pd.DataFrame(..., columns=cols) Every property below uses a deliberately garish color so you can see exactly what it controls: .. code-block:: python component_config = {'theme': { 'colorScheme': 'dark', 'accentColor': 'purple', 'accentHoverColor': 'orange', 'backgroundColor': 'blue', 'foregroundColor': 'teal', 'oddRowBackgroundColor': 'red', 'borderColor': 'pink', 'headerBorderColor': 'green', 'headerBackgroundColor': 'brown', }} .. raw:: html How theming works under the hood --------------------------------- Theme configuration flows through three layers: 1. **Python** — ``component_config['theme']`` is a dict that rides alongside the DataFrame display configuration. It's stored in ``df_viewer_config`` and serialized to JSON. 2. **CSS custom properties** — The React layer reads the theme dict and sets ``--bk-accent-color``, ``--bk-bg-color``, etc. as inline styles on the wrapper ``div``. All child components inherit these variables. 3. **AG Grid theme API** — ``backgroundColor``, ``foregroundColor``, ``oddRowBackgroundColor``, ``borderColor``, ``spacing``, and the padding scale properties are passed directly to AG Grid's ``Theme.withParams()`` method, which handles the grid's internal styling. The ``resolveColorScheme()`` function is the single source of truth for light/dark resolution. It checks ``themeConfig.colorScheme`` first; if that's ``'auto'`` or absent, it falls back to the OS preference detected via ``window.matchMedia('(prefers-color-scheme: dark)')``. After the color scheme is resolved, ``resolveThemeColors()`` merges the matching ``light`` or ``dark`` sub-dict (if present) with the top-level properties. Scheme-specific values take priority, so you can set shared defaults at the top level and only override what differs per scheme. In server mode (``mode="buckaroo"``), ``component_config`` is persisted in the session state. When a user changes the cleaning method or post-processing option, the dataflow rebuilds ``df_display_args`` from scratch — but ``component_config`` is re-applied afterward, so the theme survives interaction. Building your own theme ----------------------- Start from the closest built-in and override what you need: .. code-block:: python # Start with forced dark, customize from there my_theme = { 'colorScheme': 'dark', 'accentColor': '#your-brand-color', } # Only add background/foreground/border if the defaults don't work # for your accent color. The built-in dark/light palettes are designed # to work with any accent. Tips: - ``accentColor`` is the highest-impact single property — it controls column selection highlighting, active tab backgrounds, and button colors. - Always pair ``accentColor`` with ``accentHoverColor`` (a slightly darker shade) for consistent interaction feedback. - ``oddRowBackgroundColor`` should be close to ``backgroundColor`` — just enough contrast to distinguish rows without creating visual noise. - Use ``spacing``, ``rowVerticalPaddingScale``, and ``cellHorizontalPaddingScale`` to control density. Lower values = more compact. The defaults (``5``, ``0.5``, ``0.3``) are a good middle ground. - ``headerBorderColor`` is useful when you want headers to stand out from data rows — set it to your accent color for a subtle branded touch. - For auto light/dark, put shared values at the top level and scheme-specific colors in ``light``/``dark`` sub-dicts. - Test with actual data. A theme that looks great on 5 rows might be overwhelming on 500. Generating static theme demos ------------------------------ The embeds on this page were generated with: .. code-block:: bash python scripts/generate_theme_static_html.py This produces HTML files in ``docs/extra-html/themes/`` that reference the shared ``static-embed.js`` and ``static-embed.css`` bundles.