Skip to content

feat: support theme override via query param - #10196

Merged
mscolnick merged 1 commit into
mainfrom
kg/embed-dark-mode-query-param
Jul 17, 2026
Merged

mscolnick merged 1 commit into
mainfrom
kg/embed-dark-mode-query-param

Conversation

@kirangadhave

@kirangadhave kirangadhave commented Jul 15, 2026 •

Copy link
Copy Markdown
Member

📝 Summary

Add a theme URL query param that overrides the notebook's saved display.theme. Values are light, dark, or system; anything else is ignored and falls back to the saved config.

Until now theme was resolved solely from the notebook's saved display config (serialized into the page at serve/export time), with no way to change it per-view. This lets a deployment or embed force a theme from the URL, e.g. https://marimo.app/...?embed=true&theme=dark. It works across the run, read, and static-export paths since they all resolve through the same theme atom. system continues to follow prefers-color-scheme.

@vercel

vercel Bot commented Jul 15, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Jul 16, 2026 12:05am

Request Review

@kirangadhave kirangadhave added the enhancement New feature or request label Jul 15, 2026
@kirangadhave
kirangadhave marked this pull request as ready for review July 15, 2026 23:50
Copilot AI review requested due to automatic review settings July 15, 2026 23:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds support for overriding the UI theme via a theme URL query parameter (light/dark/system), allowing per-view theme control without changing the notebook’s saved display.theme.

Changes:

  • Add theme to KnownQueryParams and document its behavior.
  • Resolve theme from the URL query param (when present) before falling back to saved config.
  • Add Vitest coverage for query-param parsing and precedence over saved config.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
frontend/src/theme/useTheme.ts Adds query-param parsing and uses it to override the saved theme when not running as an island.
frontend/src/theme/tests/useTheme.test.ts New tests for query-param parsing and override precedence.
frontend/src/core/constants.ts Registers and documents the new theme query parameter.

Comment thread frontend/src/theme/__tests__/useTheme.test.ts Outdated
Add a `theme` URL query param (light/dark/system) that overrides the notebook's saved display.theme in the app, read, and export paths. Embedded islands are excluded: they infer their theme from the host page.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 3 files

Re-trigger cubic

@mscolnick
mscolnick merged commit a1b5ea2 into main Jul 17, 2026
30 checks passed
@mscolnick
mscolnick deleted the kg/embed-dark-mode-query-param branch July 17, 2026 15:05
kirangadhave added a commit to marimo-team/jetbrains-marimo that referenced this pull request Jul 28, 2026
## 📝 Summary

Closes #54

A user on a dark IDE theme sets marimo's **User settings → Display →
Theme** to `light`; after
restarting PyCharm it is `dark` again, and they can watch the plugin
rewrite a `marimo.toml` on every
launch.

**Fix.** Drive the theme from marimo's `theme` URL query param (added in
marimo 0.23.15,
marimo-team/marimo#10196) and stop touching config files entirely. One
rule:

> The plugin appends `?theme=light|dark` **only when marimo's resolved
`display.theme` is `system`**.
> An explicit `light`/`dark` is passed through untouched.

Inside the IDE, `system` means the IDE. marimo's own three-value
dropdown is then sufficient —
`light`/`dark` pins the notebook, `system` follows the IDE and now
tracks it *live* (previously an IDE
theme switch needed a restart to take effect). No new plugin setting:
"always override" would just
duplicate a setting marimo owns, and "never override" would leave
`system` resolving to the OS
appearance, which is the bug.

**Why read the theme back from the server.** marimo resolves
`display.theme` from four layers — user
config, `pyproject.toml [tool.marimo]`, the notebook's PEP 723 metadata,
env overrides — and already
inlines the resolved result into the page it serves as
`<marimo-user-config data-config="…">`. Reading
that is one GET and stays correct if the layering changes;
reimplementing the resolution in Kotlin, or
reading `~/.config/marimo/marimo.toml` alone, would miss per-project and
per-notebook themes.

**Why `system` can't just be left to the browser.** Verified under
`runIde` with a throwaway probe:
with the IDE in Dark (`JBColor.isBright()=false`), the embedded page
reported
`prefers-color-scheme: light` (host OS was Light). JCEF follows the
**OS** appearance, not the IDE's
look and feel — so `system` must be resolved on the Kotlin side, and an
IDE theme switch can only reach
the page via a reload.

### Behavior changes

- A user with an explicit `theme = "light"` and a dark IDE now gets
light notebooks; the IDE used to
  always win. This is the requested fix.
- Switching marimo's theme *to* `system` in an open notebook starts
IDE-following after that notebook is
  reopened — the param is decided at load.
- marimo's other settings and state are read from and written to the
user's normal config again.
`<IDE config>/marimo-theme/` is left orphaned rather than migrated: the
real config is authoritative
again, and copying the stale copy over it could clobber live settings.
Called out in the changelog.
- Following the IDE theme needs marimo ≥ 0.23.15. On older versions the
param is ignored, so the theme
comes from the user's own config — no following, but no clobbering
either.

### Changes

- **Removed** `MarimoThemeConfig` (and its test) and the
`withEnvironment` wiring in `SdkLauncher` /
  `UvLauncher`. The plugin no longer writes any marimo config file.
- **Added** `server/MarimoPageConfig` — fetches the served page and
extracts `display.theme` from the
  `data-config` attribute; null on any read/parse failure.
- **Added** `editor/MarimoThemedUrl` — the rule above as pure functions,
building the URL with
  `Urls.newFromEncoded(...).addParameters(...)`.
- **`MarimoNotebookView`** resolves the theme off the EDT before
`loadURL`, and reloads on
`LafManagerListener` only when the notebook follows the host *and* the
light/dark answer actually
changed (the LaF topic also fires for font and colour-scheme edits).
Both launch paths (SDK and uv
  sandbox) get this for free, since it sits above the launcher layer.
mscolnick added a commit to marimo-team/marimohub that referenced this pull request Jul 30, 2026
Force the embedded marimo app onto the marimohub light/dark theme via
marimo's `?theme=` query param
([marimo-team/marimo#10196](marimo-team/marimo#10196)),
so the notebook matches the chrome around it.

## Changes
- `NotebookPage.tsx`: append `?theme=light`/`?theme=dark` (from
`useTheme()`, already resolved) to the kernel iframe URL via the `URL`
API.
- The URL is memoized on `sandboxUrl` only — the theme is frozen at
load, since marimo reads `?theme=` only on load and re-deriving it live
would reload (and reset) the running app on a toggle. **Restart**
re-reads the current theme.
williambdean pushed a commit to williambdean/marimo that referenced this pull request Sep 6, 2026
## 📝 Summary

Add a `theme` URL query param that overrides the notebook's saved
`display.theme`. Values are `light`, `dark`, or `system`; anything else
is ignored and falls back to the saved config.

Until now theme was resolved solely from the notebook's saved display
config (serialized into the page at serve/export time), with no way to
change it per-view. This lets a deployment or embed force a theme from
the URL, e.g. `https://marimo.app/...?embed=true&theme=dark`. It works
across the run, read, and static-export paths since they all resolve
through the same theme atom. `system` continues to follow
`prefers-color-scheme`.

This branch was successfully deployed

1 active deployment
Preview — 4d546f17 Deployed Jul 16, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants