LearnNewsExamplesServices
Frontmatter
id18106
titlecomponent.Base#getTheme cannot see a nested theme: the vdom parent walk yields component reference nodes, whose theme class sits on the referenced root, so it falls back to the app default
stateClosed
labels
bug
assigneesneo-fable
createdAtSep 2, 2026, 4:59 PM
updatedAtSep 2, 2026, 5:46 PM
githubUrlhttps://github.com/neomjs/neo/issues/18106
authorneo-fable
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 2, 2026, 5:46 PM

component.Base#getTheme cannot see a nested theme: the vdom parent walk yields component reference nodes, whose theme class sits on the referenced root, so it falls back to the app default

neo-fable
neo-fable commented on Sep 2, 2026, 4:59 PM

Problem

src/component/Base.mjs#getTheme resolves the closest theme in three steps: the component's own cls, then VDomUtil.getParentNodes(mainView.vdom, me.id) scanning each parent node's cls for a neo-theme-* class, then the app's default theme. The second step no longer sees nested themes: a parent's vdom holds its child components as reference nodes ({componentId}), and getParentNodes collects those reference objects as the parent chain. The theme class lives on the referenced component's own vdom root, not on the reference, so the scan finds nothing and the method returns Neo.config.themes[0].

A child inside a themed scope carries the inherited theme as a config (container.Base#afterSetTheme propagates item.theme) but, by design, no class of its own (component.Base#afterSetTheme omits the carrier when the physical parent has the same theme). getTheme never consults me.theme, so the one place the answer is already known is skipped.

Consequence: the shared tooltip (tooltip.Base#applySingletonTargetConfig → resolveTargetTheme → target.getTheme()) stamps the app default on itself for any target inside a nested scope, so a light scope inside a dark app shows a dark tooltip — the contract #5698 introduced the theme walk to keep.

Evidence

Measured on a component fixture at dev@4e0e9dd8c3 (2026-09-02 14:56Z): a viewport under neo-theme-neo-dark holding a container whose class default is theme: 'neo-theme-neo-light', with a button inside. Rendered: the container carries neo-theme-neo-light; worker configs: container theme light with the class in cls; button theme light with no theme class (inherited, as designed). Hovering the button: the shared tooltip's theme reads neo-theme-neo-dark and its cls carries the dark class.

  • src/component/Base.mjs#getTheme — the three steps.
  • src/util/VDom.mjs#getParentNodes — pushes vdom.cn[i] (the reference node) into the chain; getVdom resolves references only for descent.
  • src/container/Base.mjs#afterSetTheme — propagates item.theme to children.

Change

getTheme returns me.theme when set (the propagated inherited theme is the closest theme by construction), then walks the component parent chain (parent.theme / parent.getTheme()) rather than the vdom, then falls back to the app default as today. The tooltip's DOM-path fallback stays for data-attribute targets that are not component roots.

Acceptance Criteria

  • Unit: a child without its own class inside a themed container answers getTheme() with the container's theme; a child with its own theme answers its own; a component with no theme anywhere answers the app default. Red on dev for the first case.
  • Component: hovering a target inside a light scope under a dark app stamps neo-theme-neo-light on the shared tooltip (the fixture from #18102's witness, extended by one scope); red on dev.
  • Existing tooltip and theme suites stay green.

Non-goals

  • #18105 (an item config's own theme is dropped at creation) — the sibling defect on the way in; this one is on the way out.
  • The value-sheet weight (#18102).

Sweep 14:58Z before filing: live latest-20 open (no match), A2A (no claim), Knowledge Base (#5698 is the walk's origin; #15206, #17222, #16113 mention getTheme in other contexts).

Authored by Mnemosyne (@neo-fable, Claude Fable 5.1, Claude Code) · session 37bbc610-f0cd-4abb-95c2-eb70336a86f3

tobiu referenced in commit 05ec1e2 - "fix(component): getTheme answers the closest theme through the component chain (#18106) (#18111) on Sep 2, 2026, 5:46 PM
tobiu closed this issue on Sep 2, 2026, 5:46 PM