Repository navigation
Scope the widget's NDL stylesheet so it cannot restyle the host page - #468
Merged
Merged
Conversation
FlorentinD
added this pull request to stack #469
October 8, 2026 08:28
FlorentinD
marked this pull request as draft
October 8, 2026 08:28
| // Leading/trailing whitespace and comments, kept verbatim so a license header | ||
| // on the first selector of a list survives and never leaks into the selector. | ||
| const LEADING_RE = /^(?:\s|\/\*[\s\S]*?\*\/)*/; | ||
| const TRAILING_RE = /(?:\s|\/\*[\s\S]*?\*\/)*$/; |
Base automatically changed from
gdsa-1733-neo4j-viz-graphwidget-not-rendering-in-graph-analytics
to
main
October 9, 2026 14:02
The widget applies NDL's full stylesheet at the host document level: the overlay copy in document.head used for portaled menus, and `_css` where the host mounts it document-wide. That stylesheet's Tailwind preflight has bare-element selectors (h1, a, ol/ul/menu, *, body, ...) and declares color-scheme and the lightningcss light/dark toggles on :root, so it reset the host page's own typography, links and lists and flipped Marimo's light/dark resolution (leaving the page white while Marimo stayed dark). Scope the stylesheet to the widget at build time. Bare-element selectors are rewritten to match only inside the wrapper (via :where() so specificity and the cascade are unchanged), and the root theme-state declarations are relocated to the wrapper. Class-scoped rules stay global, so overlays portaled outside the wrapper keep their styling.
Cover the scoping end-to-end in real Marimo and JupyterLab sessions, asserting the document-level NDL stylesheet has no bare-element or root theme-state rules, and guard the shipped stylesheet directly. Move marimo to the dev group so the Marimo integration test runs in CI (it is not a notebook-only dependency). The marimo example recipes rely on the implicit default group, matching the streamlit recipe.
FlorentinD
marked this pull request as ready for review
October 9, 2026 14:06
FlorentinD
force-pushed
the
gds-440-marimo-integration-is-off
branch
from
October 9, 2026 14:13
6773879 to
52c588e
Compare
Replace the backtracking-prone leading/trailing selector regexes with a linear edge scan, drop the second declaration mini-parser in favour of a plain split of the root token blocks, and reduce the shipped-stylesheet guard to targeted regex checks instead of a reimplemented CSS tokenizer. Behaviour is unchanged: the rebuilt resources are byte-identical.
Replace the hand-rolled CSS tokenizer (brace/string/comment scanning, selector list splitting) with postcss. postcss already ships in the tree via vite, so this adds no new packages, and it handles the structure (comments, at-rules, nested rules, paren-aware selector lists) that both of the bugs we hit during development lived in. Only the scoping policy stays ours. Behaviour is unchanged: the rebuilt resources are byte-identical.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #467 (base branch
gdsa-1733-neo4j-viz-graphwidget-not-rendering-in-graph-analytics).Problem
The graph widget restyles its host page in Marimo notebooks: the widget renders fine, but Marimo's own typography, links and lists get reset and the page turns white while Marimo stays in dark mode.
Root cause
The widget applies NDL's full stylesheet at the host document level — the overlay copy in
document.headused for portaled menus, and_csswhere the host mounts it document-wide. That stylesheet's Tailwind preflight has bare-element selectors (h1,a,ol,ul,menu,*,body, …) and declarescolor-schemeplus the lightningcss light/dark toggles on:root. Against Marimo's own low-specificity element styles the preflight wins, and the root theme-state flips Marimo'slight-dark()resolution.Fix
Scope the NDL stylesheet to the widget at build time (a Vite plugin applied to all three builds):
:where([data-neo4j-viz-ndl]) …), so specificity and the cascade inside the widget are unchanged.color-scheme,--lightningcss-*) are relocated from:root/:hostto the wrapper..ndl-*,.cm-*, …) stay global, so overlays portaled outside the wrapper (menus, tooltips) keep their styling.Testing
ndl-css-scope.test.ts— transformer unit tests.test_widget_marimo_browser.py— new Playwright e2e against a real Marimo server; asserts the document-level NDL stylesheet has no bare-element or root theme-state rules.test_widget_browser.py— same assertion added to the JupyterLab e2e.test_style_css_scope.py— direct guard on the shippedstyle.css.devgroup so the integration test runs in CI.Verified the guards fail against the pre-fix stylesheet (100 bare selectors + 3 theme-state) and pass after.
just py-test(323 passed) andjust js-test(67 passed) are green.