Capítulo 6 de 43

Chapter 6: Styling

Core Idea

Radix Primitives are fully unstyled — you're responsible for both functional and presentational styles, applied via the className prop each part accepts, with component state exposed through data-state/data-* attributes.

Key Concepts

  • className pass-through: every part accepts className, forwarded directly to its DOM element — the only styling hook you need for plain CSS.
  • data-state attribute: stateful parts expose their state (e.g. data-state="open" on an open Accordion Item) so CSS/CSS-in-JS can target state without JS.
  • Functional styles are your responsibility: even layout-critical styles (e.g. a Dialog Overlay covering the viewport) are not built in — Radix ships zero CSS by design.
  • Extending a primitive: wrap a part with React.forwardRef and pass props through, same pattern as any custom React component wrapping a library component.

Code Examples

.AccordionItem {
  border-bottom: 1px solid gainsboro;
}
.AccordionItem[data-state="open"] {
  border-bottom-width: 2px;
}
  • What it demonstrates: styling a stateful part purely via its data-state attribute, no JS state tracking needed.

Key Takeaways

  1. Nothing renders correctly by default — plan for functional styles (positioning, sizing) as well as visual styles from day one.
  2. data-state (and other data-* attributes documented per-component) is the idiomatic way to style state transitions, works identically with plain CSS, CSS Modules, or CSS-in-JS.
  3. Extending/wrapping a primitive part is just standard forwardRef component wrapping — no special Radix API needed.

Connects To

  • Animation: builds directly on data-state for CSS keyframe animations tied to mount/unmount state.
  • Composition: asChild is the mechanism for going beyond className when you need full control of the rendered element.