LearnNewsExamplesServices
Frontmatter
id18105
titlecontainer.Base#createItem drops an item config''s own theme: the object branch assigns the class default or the parent''s over it, while the class branch keeps it
stateClosed
labels
bug
assigneesneo-fable
createdAtSep 2, 2026, 4:55 PM
updatedAtSep 2, 2026, 5:45 PM
githubUrlhttps://github.com/neomjs/neo/issues/18105
authorneo-fable
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 2, 2026, 5:45 PM

container.Base#createItem drops an item config's own theme: the object branch assigns the class default or the parent's over it, while the class branch keeps it

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

Problem

A container item declared as a config object with its own theme never gets it. src/container/Base.mjs#createItem, object branch:

item.theme = defaults.theme || module.config.theme || me.theme

The right-hand side never consults item.theme, so an explicit theme: 'neo-theme-neo-light' on an item config under a dark parent is overwritten with the class default (usually null) or the parent's theme. The class branch a few lines above keeps it — Neo.create({theme: item.config.theme || me.theme, ...defaults, module: item, ...config}) spreads the instance config last — so the two ways of declaring the same item disagree.

Nested themes are the documented feature ("a dark-themed grid inside a light-themed panel" in the styling guide), and a child carrying its own theme is how the shared tooltip decides which theme class to stamp on itself (component.Base#getTheme walks the parents' classes).

Evidence

Measured on a component fixture (2026-09-02 14:53Z, dev@4e0e9dd8c3): a Container item config with theme: 'neo-theme-neo-light' inside a viewport under neo-theme-neo-dark rendered with classes neo-container neo-flex-container … — no theme class — and Neo.worker.App.getConfigs({id, keys: ['theme']}) on its button read [null]; hovering that button stamped neo-theme-neo-dark on the shared tooltip. The same fixture with the theme moved to a subclass's class config (module.config.theme) renders the class and stamps the light theme.

  • src/container/Base.mjs:400–405 (class branch, instance config wins) vs :452 (object branch, instance config overwritten).
  • The line's origin: #6637 made class-config themes win over the parent's during createItem — it never considered an explicit item theme.

Change

item.theme = item.theme || defaults.theme || module.config.theme || me.theme in the object branch — an explicit item config outranks itemDefaults, the class default and the parent, in that order, which is the precedence every other item config key already has.

Acceptance Criteria

  • Unit: a container under a dark theme creating {module: Component, theme: 'neo-theme-neo-light'} yields a child whose theme is the light one and whose cls carries it; red on dev.
  • Unit: a child without its own theme still receives itemDefaults.theme, then the class default, then the parent's — unchanged precedence for the existing cases.
  • Lazy-loaded items (module as a loader function) keep their current path.

Non-goals

  • The functional component path (examples/functional/hostComponent/Component.mjs sets a theme on a vdom child) — a different creation route, not measured here.
  • The value-sheet weight question (#18102), which surfaced this while building its witness.

Sweep 14:54Z before filing: live latest-20 open (no match), A2A (no claim), Knowledge Base (#6637 is the line's origin, #5698 the tooltip's theme walk — neither this).

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

tobiu referenced in commit 61b0a05 - "fix(container): an item config's own theme survives creation (#18105) (#18110) on Sep 2, 2026, 5:45 PM
tobiu closed this issue on Sep 2, 2026, 5:45 PM