Why this fires¶
Every @(expr) value travels as a CSS custom property on the component's root element — the element literal in tail position of the fn body. Custom properties inherit down the DOM, so every descendant of the instance reads its own root's value. A component whose view has no element root of its own — it delegates everything to a child component, returns a stored value, or ends in a fragment — gives the values nowhere to ride.
let accent = "red"
fn Broke() -> View {
let v = <div class="a"><style>.a { color: @(accent); }</style></div>
v
}
// error[TE737]: `@()` needs a root element to carry its value; this component's view has noneFix it¶
Make the tail expression an element literal:
fn Fixed() -> View {
<div class="a">
<style>.a { color: @(accent); }</style>
</div>
}Wrapping a delegated view in a <div> (or any element) also works — the wrapper becomes the property carrier. If the style needs no interpolation at all, remove the @() and the requirement disappears with it.