Skip to content

feat: Radix theming base - #12

Merged
dzole0311 merged 8 commits into
mainfrom
feat-radix-theme-base
Jul 24, 2026
Merged

feat: Radix theming base#12
dzole0311 merged 8 commits into
mainfrom
feat-radix-theme-base

Conversation

@dzole0311

@dzole0311 dzole0311 commented Jul 24, 2026

Copy link
Copy Markdown
Member

Contributes to: #7

First part of the theming work we discussed to get feedback on the shape of the theme API. It sets up a manywidgets-owned theming before revamping the existing widgets to use it. The PR git diff is bloated due to auto-generated Radix tokens file. Some pieces/ideas are ported from the draft PR: #1

I used Codex to work on the idea outlined below.

Main changes:

  • Set up shared theming for manywidgets
  • Supports full themes with theme=
  • Supports small overrides with style=
  • Adds Radix-based tokens and values + light and dark defaults and keeps the public API in --mw-* so we are not tied to Radix internals

@batpad The default token set is derived/auto-generated from Radix (names, scales and values) and then used with the manywidgets --mw-* namespace. The priority is: MySt variable if available > JupyterLab variable if available > Radix-derived manywidgets fallback.

Intended usage:

  1. If used directly, widgets will work with their default styling e.g. Slider()
  2. If a full theme change is needed, Slider(theme=dark) can be used
  3. For small local overrides, style= can be used on top e.g: Slider(theme=light, style={"--mw-color-accent": "#7c3aed"}). In that case, the widget uses the light theme but overrides only the accent color.
  4. If there's a need for a fully custom theme, then custom = Theme(color_accent="#7c3aed") and then Slider(theme=custom) should work
  5. If there's a need for existing theme to be customized, then custom = light.extend(color_accent="#7c3aed", radius_4="12px") and then Slider(theme=custom) should work

Some context:

  • Radix is used as the source for the default token values and scales but the public API is owned by manywidgets --mw-* variables. That keeps the theme contract part of manywidgets but also gives us mature defaults instead of inventing the whole token system from scratch (fully hand-rolling custom tokens from scratch, including token names, accessible values etc. needs a lot of more design/a11y thinking, which Radix already covers)
  • I avoided depending on @radix-ui/themes at runtime because it brings React peer dependencies
  • Considered using Open Props: https://open-props.style/ / https://github.com/argyleink/open-props. It has a lot of useful CSS variables but I’m not sure about the maintenance of the project and how strong it is compared to Radix for this use csae
  • @batpad I also considered Tailwind because MyST themes seem to use Tailwind so it may be a better long-term alignment point than Radix. I did not switch this PR to Tailwind because MyST currently exposes its own runtime variables like --myst-color-* and not the full Tailwind token set. So this PR already prefers those MyST variables first, then JupyterLab variables, then manywidgets fallbacks (Radix-based). So the current --mw-* layer should still work well with MyST and we can swap the generated fallback values from Radix to Tailwind later if that feels like the better direction. Tailwind also I think will need more integration and feels like a different styling paradigm with utility classes etc.

Local test

ligh-dark-theme.mov

Proposed next steps:

  • Follow up with a second PR that starts converting existing widget CSS to consume the --mw-* tokens
  • Add example adapter for third-party renderers like Chart.js where CSS variables do not automatically flow into canvas/WebGL config
  • Add docs for widget authors (which tokens to use, when to add component-specific tokens and how users should create/apply themes)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@batpad auto-generated with scripts/generate_radix_tokens.mjs

Comment thread .gitattributes

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this to mark the generated token file as generated code so GitHub can exclude it from language stats and de-emphasize it in review. I was hoping it would also reduce the visible lines-changed count in the PR bar but it looks like GitHub still includes it there

@dzole0311
dzole0311 requested review from batpad and wrynearson July 24, 2026 07:17

@batpad batpad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me!

@dzole0311
dzole0311 merged commit b60c5c0 into main Jul 24, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants