@syncropel/react
v0.1.0
Published
React components for the Syncropel protocol — a constrained palette of 21 atoms and molecules with tokens-customizable, structure-frozen defaults. Renders @syncropel/projections documents natively.
Maintainers
Readme
@syncropel/react
React components for the Syncropel protocol. A constrained palette of 17 atoms + 4 molecules with tokens-customizable, structure-frozen defaults. Designed as the render target for declarative UI documents from @syncropel/projections — and equally usable on its own.
import "@syncropel/react/styles.css";
import { Card, Column, Heading, Stat, Grid } from "@syncropel/react";
export function Dashboard() {
return (
<Card padding="lg">
<Column gap="md">
<Heading level={2}>Session summary</Heading>
<Grid cols={3} gap="sm">
<Stat label="Tracks played" value={47} />
<Stat label="Artists" value={14} delta={3} />
<Stat label="Transitions" value={12} />
</Grid>
</Column>
</Card>
);
}Philosophy
Most design systems optimize for developer freedom: any prop, any override, any combination. This one optimizes for guarantees — the kind you need when a UI might be generated by an LLM or described in a JSON document and you still want it to render correctly.
- Tokens customizable. Rebrand colors, typography, spacing via CSS custom properties at
:root. No rebuild required. - Structure frozen. Component shapes and defaults are fixed. No
classNameescape hatches, no off-scale pixel values, no arbitrary variants. - Closed palette. Growth through reviewed spec proposals, not consumer-side overrides. 21 primitives today; new primitives are added deliberately, not opportunistically.
- Serializable by design. Every component's props can survive a JSON round-trip — which is exactly why the schema package (
@syncropel/projections) can describe them declaratively.
Install
npm install @syncropel/reactPeer dependencies: react >= 18, react-dom >= 18. Runtime dep: @syncropel/projections (for schema types used by Text's inline-markdown parser).
Import styles once at your app root:
// app/layout.tsx or pages/_app.tsx
import "@syncropel/react/styles.css";For non-React iframes that want the tokens without React:
<link rel="stylesheet" href="https://unpkg.com/@syncropel/react/dist/tokens.css" />What's in the palette
Atoms (17)
| Component | Role |
|---|---|
| Button | Text-label button — 4 variants, 3 sizes, loading affordance |
| IconButton | Icon-only button — ariaLabel required at type level |
| CopyButton | Click-to-copy with 1.5s confirmation |
| Chip | Compact metadata chip with optional leading glyph |
| Code | Monospace inline or block (<code> / <pre><code>) |
| Column | Vertical flex container |
| Divider | Horizontal / vertical separator |
| Glyph | Semantic Unicode symbol (acts, domain objects, thread states, AITL) |
| Grid | Two-dimensional grid (cols 1–12) |
| Heading | Semantic heading h1–h6 with enforced size mapping |
| KeyValue | Horizontal label + value row (settings, metadata) |
| Link | Navigational anchor with focus ring + hover underline |
| Pulse | Inline loading ellipsis |
| Row | Horizontal flex container |
| Skeleton | Rectangular / circular / text loading placeholder |
| StatusDot | Colored state indicator dot |
| Text | Paragraph / inline text; parses inline markdown subset in string children |
Molecules (4)
| Component | Role |
|---|---|
| Card | Bordered container with token-scale padding; optional interactive state |
| EmptyState | Fallback when a list / region has no content |
| ErrorState | Error fallback with optional retry |
| Stat | Label + big value + optional delta (dashboard-grade metric display) |
More molecules (RecordLine, InlineForm, TabBar) ship in a minor bump.
Token customization
Override any value at :root (or any ancestor) to retheme:
:root {
--accent: #0ea5e9;
--bg-primary: #ffffff;
--text-primary: #111827;
--font-mono: "JetBrains Mono", ui-monospace, monospace;
}Tokens cover: color palette (earth-mineral by default; copper accent), typography scale (7 sizes, 3 weights), spacing scale (8 units), motion durations, border radii. See dist/tokens.css for the full list.
Inline markdown in Text
<Text> parses a narrow markdown subset when children is a string — **bold**, *italic*, `code`, [link](url), ~~strike~~. This lets both humans and language models write expressive copy without nested React trees:
<Text>
Visit **example.com** or read the [docs](/docs) for `emit()` examples.
</Text>Renders with a bold span, a link (routed through <Link>), and an inline <Code> automatically.
Related packages
- @syncropel/sdk — emit + query records against the Syncropel protocol
- @syncropel/projections — declarative UI document schema; these components render it
