Components
@nimblebrain/synapse/ui is a React component library for embedded Synapse
apps. You get a token contract, layout primitives, a handful of data-display and
interactive components, and three responsive layout scaffolds. Import them and
your app inherits the look of whatever host it renders in: no theme wiring, no
brand baked into your bundle.
import { Card, Table, Badge, Button } from "@nimblebrain/synapse/ui";Design principles
Section titled “Design principles”These are the durable decisions behind the library. They rarely change, and they explain why the components behave the way they do.
-
The library holds no brand. Every color, font, radius, and shadow is a
var(--token, neutralFallback)reference, never a hex value. The host injects the real palette and fonts at runtime through the ext-appshostContext.styles.variables, so the same app adopts the NimbleBrain host, a ChatGPT surface, or your own runtime without changing a line. Standalone, with no host to inject anything, the components render in neutral fallbacks: system fonts, neutral grays, a generic blue. -
Theme via CSS, not React. Components style with token-driven inline-style objects whose values are those
var()references. When the host swaps the:rootvariables (including a light-to-dark flip), everyvar()re-resolves in CSS and the pixels change with no React re-render. Keyframes and pseudo-state rules inject once; brand values are never captured in component state. -
Scaffold only genuinely-complex layouts.
AppFrame,SidebarLayout, andListDetailLayoutexist because each one encapsulates real responsive and stateful complexity worth owning once. Boards, grids, and simple lists are not components. They are primitives plus a recipe. The library codifies the shapes apps actually take, not a general-purpose layout engine. -
Responsive to the pane, not the device. Layouts observe their own width with a
ResizeObserver(viauseBreakpoint), never the viewport. An app’s iframe might be fullscreen, split down the middle, or docked in a narrow rail regardless of screen size, so device media queries would be measuring the wrong box. -
Lean on the platform.
Draweris built on the native<dialog>element, which brings focus-trapping, Escape-to-close, and scroll behavior for free rather than re-implemented in JavaScript. Where the browser already solves a problem, the library uses it.
The library
Section titled “The library”Every component has its own page with live previews, props, and copy-paste code.
Foundations: the contract everything else reads from.
- Tokens: the
var(--token, fallback)model, every token group, and how the host fills them. - Fonts: the two side-effect imports that load the brand faces and establish the root-height chain.
Layout primitives: the low-level flow and spacing pieces.
- Stack: vertical flow with a token-sized gap.
- Inline: horizontal flow that wraps and aligns.
- Spacer: a flexible gap that pushes siblings apart.
- Divider: a hairline rule between sections.
Layout scaffolds: the responsive shells for whole views.
- AppFrame: the outer app shell (header, body, root-height chain, base reset applied automatically).
- SidebarLayout: a sidebar beside a main pane that collapses when the pane gets narrow.
- ListDetailLayout: a list and a detail view side by side, stacking on a narrow pane.
Typography: the type scale in prose form.
- Heading: the display scale (
sm,md,lg) in the heading face. - Text: body copy at four sizes with muted and faint tones.
- Prose: a container that styles a block of rich or Markdown-rendered content.
Data display: the components that render your data.
- Card: a surface that groups related content.
- ListRow: a single list row with leading and trailing slots.
- Table: a token-styled data table.
- Avatar: a user or entity image with an initials fallback.
- Badge: a small status or category label.
- StatusDot: a colored dot for compact status.
- Pagination: page controls for long collections.
Interactive: the components users act on.
- Button: a pressable action in three variants.
- TextLink: a chrome-less text button for inline actions.
- SearchField: a search / filter input.
- SegmentedControl: single-select among a few options.
- Drawer: an overlay panel built on native
<dialog>.
Feedback: the components that report state.
- Spinner: an indeterminate loading indicator.
- EmptyState: a placeholder for empty or zero-result views.