<node>
<node> is the plain container: one bevy_ui Node entity that takes a
style, lays out its children with flexbox or grid, and reports pointer
events. There are no divs or spans; every layout is built from <node>.
Most of this page (the style prop, state styles, events, identity props)
applies to every styled element, <button>, <text> and <image>
included.
Usage
<node style={{ flexDirection: "row", gap: 12, padding: 16 }}>
<node style={{ width: 48, height: 48, backgroundColor: "#7aa2f7" }} />
<node style={{ width: 48, height: 48, backgroundColor: "#9ece6a" }} />
</node>A <node> starts with Bevy's defaults: a flex container laid out as a row,
sized by its content, with a transparent background, and passing the
pointer through to whatever is behind it. Arrange children with
flexbox, grid or
positioning, and size and space them with
sizing and spacing.
Top-level layout
Elements rendered at the top of your React tree are children of a window-filling flex column that centers them horizontally and spaces them 16px apart. To lay out the whole window yourself, render a single node that fills it:
export function App() {
return <node style={{ width: "100%", height: "100%" }}>{/* … */}</node>;
}Common props
| Prop | Effect | Details |
|---|---|---|
style |
Layout and paint, as a BevyStyle object |
Style properties |
hoverStyle, pressStyle, focusStyle |
Style overlays for interaction states | State styles below |
onClick, onPointer* |
Click, drag and hover events | Mouse |
onWheel |
Raw wheel deltas over the element | Mouse |
scrollTop, scrollLeft, scrollStep |
Controlled scrolling of an overflow: "scroll" container |
Overflow |
onScroll |
The scroll offset changed | Overflow |
name |
Names the Bevy entity, so Rust systems can find it | Named nodes |
sharedTag |
Shared-element identity across unmount and mount | Shared elements |
key |
React's list key | React |
Not every element takes every group: <editableText> has no pointer, scroll
or wheel props, <root> and nested <text> spans take only style, name,
sharedTag and key. A prop outside an element's groups is ignored with a
propIgnored devtools warning. The element reference lists the groups per
element.
Every prop crosses to Bevy only when its value changes, so re-rendering
with the same props costs nothing on the Bevy side. Unsetting a style
property returns it to the element's default (for example focusPolicy
returns to "block" on a <button>).
State styles
hoverStyle, pressStyle and focusStyle overlay the base style while
the element is in that state. They are applied on the Bevy side: no React
state, no re-render.
<node
style={{
padding: 12,
borderRadius: 8,
backgroundColor: "#24283b",
transition: { backgroundColor: { duration: 150 } },
}}
hoverStyle={{ backgroundColor: "#414868" }}
pressStyle={{ backgroundColor: "#565f89" }}
/>- The overlays stack in order:
style, thenhoverStylewhile hovered, thenpressStylewhile pressed (a pressed element is also hovered), thenfocusStylewhile focused, sofocusStylewins any conflict. - A state style carries any style property and only changes what it sets. When the state ends, those properties return to the base style.
- With a
transitionon the base style, state changes ease instead of snapping. See Style transitions. - Hover covers every element under the pointer, from the topmost down to the
first one that blocks (
focusPolicy: "block"). A hovered child keeps its pass-through ancestors hovered too, but a<button>on top un-hovers everything beneath it, its ancestors included. pressStylefollows the primary mouse button or a touch. It stays applied from the press until the release, even if the pointer leaves the element meanwhile.{ animated }bindings work in the basestyleonly. A binding in a state style is ignored with astyleBindingwarning.- Only
<editableText>takes focus on its own (by click orautofocus). On other elements,focusStyleapplies only while your Rust code gives the entity Bevy'sInputFocus.
Pointer behavior
- A
<node>passes the pointer through by default. Even with anonClick, a press also reaches what is behind it, including the 3D scene, so a camera drag can start under your panel. Use a<button>orfocusPolicy: "block"for controls and panels that should catch the pointer. See Focus policy. - Clicks do not bubble. A click goes to the topmost element under the
pointer that has an
onClickor anyonPointer*handler, or is a<button>or<editableText>, and to no other element. Clicking a<text>label inside a clickable node fires the node'sonClick. onPointer*handlers alone make an element own clicks: a child with onlyonPointerEnterswallows clicks meant for anonClickancestor.
Limits
- No CSS cascade: styles never inherit from a parent
<node>, text styles included. Share style objects in JavaScript instead. - Children are laid out by Bevy's flexbox and grid only; there is no inline or block flow.
See <node> in the element reference, and
Common props for every shared prop's
type.
bevy-react