Overview
Compound anatomy
Every SDK primitive follows the same shape: a .Rootthat owns state, plus a bag of consumer parts for rendering that state. If you've used Radix, this will feel familiar.
Shape of a primitive
A primitive is a namespaced object, not a single component. Import it once and destructure the parts you need:
import { RevenueCard } from "@get-asset/sdk";<RevenueCard.Root year={2026}><RevenueCard.Loading>Loading…</RevenueCard.Loading><RevenueCard.Error><RevenueCard.ErrorMessage asChild><p /></RevenueCard.ErrorMessage><RevenueCard.Retry>Retry</RevenueCard.Retry></RevenueCard.Error><RevenueCard.Success><RevenueCard.Revenue /><RevenueCard.Change /></RevenueCard.Success></RevenueCard.Root>
State parts
.Loading, .Error, .Success, and (on some primitives) .Empty are lightweight conditional wrappers — they render their children only when the parent is in the matching state.
These parts don't accept props. Styling and markup is your job — wrap them with your own elements.
Value parts
Parts like .Revenue, .Change, .StartingBalance render a raw number inside a <div> by default. Use them to get the data into the DOM; format it by nesting your own element via asChild.
Composing with asChild
Any slottable part accepts asChild. When set, the part clones its single child and forwards the data, class names, and event handlers onto it instead of rendering its own wrapper.
<RevenueCard.Revenue asChild><span className="text-4xl font-bold">{/* replaced with the number */}</span></RevenueCard.Revenue>
This is the primary extension point: you get all the data and state management for free, and the rendered DOM is entirely your own.