DOCS / UI REFERENCE
Styling
Styling is a Tailwind-style utility subset, resolved in JS by the tw() resolver — C++ only ever sees final style objects. Classes compose left to right; unknown classes warn once in dev instead of failing.
Supported classes
| FAMILY | CLASSES |
|---|---|
| Flexbox | flex-row flex-col flex-1 flex-auto flex-none grow shrink-0 flex-wrap items-* justify-* self-* basis-* |
| Sizing & spacing | w-* h-* size-* (width + height together) min-w-* max-h-* p-* px-* pt-* m-* mx-* mt-* gap-* gap-x-* gap-y-* — 4px scale, fractions (w-1/2), w-full, arbitrary w-[220], negatives -mt-2 -left-1/2 |
| Position | absolute relative inset-* inset-x-* inset-y-* top-* right-* bottom-* left-* |
| Color | bg-* text-* border-* — the full Tailwind palette (all 22 families, 50–950), theme tokens, hex bg-[#0B0B0A], opacity suffix bg-black/40 |
| Borders & radius | border border-2, per side border-t border-b-2 border-l-[3] (square strips — corner radii ignored), rounded rounded-sm…3xl/full, per corner rounded-t-lg rounded-br-full, arbitrary rounded-[10] |
| Gradients | bg-gradient-to-t/tr/r/br/b/bl/l/tl bg-gradient-radial bg-gradient-conic with from-* via-* to-* (palette, tokens, or from-[#111]) |
| Transforms | rotate-45 -rotate-90 rotate-[10.5] scale-95 scale-[1.25] translate-x-4 -translate-y-2, percent of own size translate-x-1/2, origin origin-top-left etc. (since 0.0.25) — layout is untransformed, but painting and hit-testing follow the transform (since 0.0.20) |
| Stacking | z-10 z-[3] -z-1 — reorders both painting and hit-testing among siblings (tree order breaks ties) |
| Visibility | hidden (display: none — leaves layout entirely) vs invisible/visible (keeps its space, paints nothing, takes no input) |
| Typography | text-xs…text-6xl text-[15] font-normal/medium/semibold/bold font-mono text-left/center/right tracking-* tracking-[3] leading-* leading-[18] truncate line-clamp-3 uppercase/lowercase/capitalize underline line-through |
| Effects | opacity-* shadow…shadow-xl shadow-inner overflow-hidden overflow-y-scroll overflow-x-scroll overflow-auto aspect-square cursor-pointer/text/default/grab/move/ns-resize/ew-resize/crosshair pointer-events-none/auto select-text/none border-solid/dashed/dotted object-contain/cover/fill |
| Filters | blur-sm…blur-3xl blur-[6] (CSS filter: blur — the node and its subtree render offscreen and soften) backdrop-blur-sm…backdrop-blur-3xl backdrop-blur-[10] (frosted glass: blurs whatever is painted beneath the node — pair with a translucent bg-* tint) |
| Motion | transition transition-all/colors/opacity/transform/none duration-150 delay-75 ease-linear/in/out/in-out — style changes tween from their currently displayed values instead of jumping. Presets: animate-spin animate-pulse animate-bounce animate-none. One honest limit: native hover:/active: merges don't transition — animate hover with onMouseEnter state instead |
| Variants | hover: active: focus: — resolved to native hover/active/focus style layers, applied by the C++ hit-tester with no JS round-trip |
Composing classes — cx()
For conditional classNames the SDK ships cx, a tiny clsx: strings, arrays, and object maps, falsy values dropped.
import { cx } from "@vsreact/core";
<View className={cx(
"px-4 py-2 rounded-lg",
active && "bg-lime-400",
{ "opacity-40": disabled },
)} />Theme tokens
Register your palette once and use semantic names everywhere — the resolver expands them like any other color:
import { configureTheme } from "@vsreact/core";
configureTheme({
colors: {
surface: "#0F1210",
raised: "#161B17",
accent: "#C6F135",
text: "#ECF2E8",
faint: "#8B948C",
},
});
// then: <View className="bg-surface border-raised hover:bg-raised">
// <Text className="text-accent" />accent is special: since 0.0.27 every built-in control paints its value with it — knob arcs, slider fills, meters, the keyboard's active keys, the envelope editor. One token themes the whole panel, and you only pass a colour prop where you want a control to differ. Without a theme they stay VSReacT lime. Reading it yourself, for custom controls that should match: accentColor(), or accentColor("66") for a translucent fill.
Custom fonts
fontFamily is a system-font lookup by default. Since 0.0.27, registerFont({ family, src }) registers a bundled typeface from font-file bytes — src is a file path or a base64 data: URI, like images. fontFamily resolves against registered families before the system lookup; unregistered names behave exactly as before. An optional weight (default 400, "bold" → 700) tags the face.
import { registerFont } from "@vsreact/core";
registerFont({
family: "Panel Grotesk",
src: "data:font/otf;base64,T1RUTwAK...", // or a .ttf/.otf file path
});
// then: <Text style={{ fontFamily: "Panel Grotesk" }} />The style prop
For computed values, pass style directly — the same keys the resolver produces (width, backgroundColor, fontSize, opacity…). Classes and style merge, with style winning.
<View
className="rounded-full bg-zinc-800"
style={{ width: size, height: size, opacity: fadeIn }}
/>Arc painting (knobs)
Two style families exist only as style keys:
- Arcs —
arcTrackColor,arcColor,arcStart,arcEnd,arcValueStart,arcValueEnd,arcThickness: the natively painted knob arc, angles in degrees around the View’s center. The built-inKnobuses −135°…+135°;arcValueStartis what powers its bipolar mode. Strokes default to rounded caps, which turn short slices into capsule blobs — setarcCap: "butt"(since 0.0.18) for radial tick marks and crisp dashes. - Text input chrome —
caretColor,placeholderColor. - Gradients (structured) — beyond the classes:
gradientType(linear|radial|conic),gradientAngle(CSS degrees, 0 = up, clockwise),gradientStops([{ offset: 0, color: "#ff0000" }, …]) for more than three stops. Radial fills are farthest-corner ellipses; conic renders are cached per size + spec. - Shadows — outer
shadowColor/Radius/OffsetX/OffsetY(path-shaped), insetinsetShadowColor/Radius/OffsetX/OffsetY(CSSbox-shadow: inset), and glyph-shapedtextShadowColor/Radius/OffsetX/OffsetYon<Text>(CSStext-shadow— LED glows without a bounding-box halo). - Shadow stacks —
boxShadow(since 0.0.27): an array[{ color, radius, offsetX, offsetY, inset? }, …]stacks multiple shadows on one node in CSS order — outer entries paint behind the background,inset: trueentries over it. Composes with the flatshadowColorkeys. - Background layers —
backgroundLayers(since 0.0.27): an array of gradient/color specs painted over the base background in order, each entry using the same keys as the structured gradients above — multi-layer metallic knob caps in one View. - Text stroke & length —
textStrokeColor+textStrokeWidth(since 0.0.27) stroke the glyph outline under the fill (CSSpaint-order: stroke);textLengthscales a single line horizontally to a fixed width (SVGtextLength/lengthAdjust), so digit readouts hold their box as the digits change. - Transforms —
rotate(degrees),scale,translateX/Y, applied about the frame centre in CSS order (translate → rotate → scale); children inherit. Layout is untransformed, but since 0.0.20 hit-testing follows the transform, so rotated controls receive input where they actually paint. - Clip polygons —
clipPolygon: a flat[x, y, x, y, …]array in percent of the frame (CSSclip-path: polygon()). Shapes the background, borders, shadows, and overflow clipping — beveled LED segments, chamfered plates, meters. - Repeating gradients —
gradientRepeat: Ntiles the stop pattern N times across the span (any gradient type): knurl rings, scanlines, ruler ticks.
<View
className="items-center justify-center"
style={{
width: 72, height: 72,
arcTrackColor: "#2A2F27", arcColor: "#C6F135",
arcStart: -135, arcEnd: 135,
arcValueEnd: -135 + 270 * value,
arcThickness: 6,
}}
/>className cost one map lookup. Hover/active/focus variants repaint natively — the JS side is not involved after mount.