Components

v0.2 · Refined baseline

Primitives, the Espanda way.

Flat fills, warm cream surfaces, ink-toned borders. No gradients on interactive surfaces. No decorative glows. Confidence comes from solid colour and clean type — the way print works, not the way SaaS dashboards usually do.

Button

Solid Beat for primary, solid Ink for secondary, no gradients anywhere. Hover deepens; press scales 2 %.

#button

Variants

Sizes

With icons

States

Usage

import { Button } from "@/components/ui/button";

<Button>New project</Button>
<Button variant="secondary">Cancel</Button>
<Button variant="danger">Delete</Button>
<Button size="lg">Get started</Button>

Input

Quiet at rest, decisive on focus. The border deepens to ink on focus — no glow, no ring.

#input

Variants

Numbers only.

Use a valid email format.

Usage

import { Input } from "@/components/ui/input";

<Input label="Email" type="email" placeholder="priya@studio.in" />
<Input label="Search" prefixSlot={<Search size={14} />} placeholder="..." />
<Input label="Project" error="Already exists" />

Textarea

Same border / focus model as Input, multi-line.

#textarea

Default

Beat will scaffold a project from this brief.

Usage

import { Textarea } from "@/components/ui/textarea";

<Textarea
  label="Brief"
  placeholder="..."
  helper="Beat will scaffold a project from this brief."
/>

Card

Flat cream surface, warm Ink border. On hover, the border deepens — no shadow, no lift. Optional 2-px accent stripe at the top in any lexicon hue.

#card

With agent accents + interactive

Acme Co. landing page

Web design · Mar — Apr 2026

8 of 12 tasks complete. Two waiting on client approval.

In progress

Acme Co. invoice #2026-04-08

₹85,000 · Sent 6 April · Due 21 April

Pulse will retry payment reminder in 3 days.

Paid

Plain (no accent)

Plain card

For neutral / utility surfaces.

No accent stripe, no agent colour. Just the warm cream surface and ink border.

Usage

import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/ui/card";

<Card accent="beat" interactive>
  <CardHeader>
    <CardTitle>Acme Co. landing page</CardTitle>
    <CardDescription>Web design · Mar — Apr 2026</CardDescription>
  </CardHeader>
  <CardContent>...</CardContent>
  <CardFooter>...</CardFooter>
</Card>

Badge

Tinted soft background + matching border. Add `dot` for live status. Each lexicon agent has its own variant.

#badge

Status variants

DefaultSolidOutlinePaidPendingOverdueInfo

Lexicon agents

Beat · ProjectsPulse · FinanceWave · ContentSpark · SalesHum · AdminEcho · CommsSurge · GrowthDrift · Discovery

Sizes

SMBASELARGE

Usage

import { Badge } from "@/components/ui/badge";

<Badge variant="beat" dot>In progress</Badge>
<Badge variant="success" dot>Paid</Badge>
<Badge variant="danger">Overdue</Badge>

Avatar

Solid lexicon hue derived from a hash of the name. Same name → same colour, every time. No gradient, no shadow — just a cream ring at the edge for separation.

#avatar

Sizes

PMPMPMPMPM

Different names → deterministic colour

PMMSAKTIVRAPSKNI

Avatar stack

PMMSAKTI+2

Usage

import { Avatar, AvatarStack } from "@/components/ui/avatar";

<Avatar name="Priya Mehta" />
<Avatar size="lg" src="/avatars/priya.jpg" name="Priya Mehta" />

<AvatarStack
  max={4}
  people={[
    { name: "Priya" }, { name: "Mira" },
    { name: "Aarav" }, { name: "Tara" }, { name: "Vihaan" },
  ]}
/>

Alert

A 2-px stripe on the left, a colour-matched icon, and a tinted soft background. Variants map to lexicon semantic colours.

#alert

Variants

Dismissible

Usage

import { Alert } from "@/components/ui/alert";

<Alert variant="success" title="Pulse marked Acme invoice as paid">
  ₹85,000 received this morning.
</Alert>

<Alert variant="warning" onDismiss={() => setOpen(false)}>
  Two overdue tasks.
</Alert>

Stat card

The dashboard atom. The value sits in solid Ink, the label in mono uppercase. A 2-px accent stripe at the top names the agent. No gradient text, no radial wash.

#stat-card

Dashboard row

Active projects

14

+3 this monthBeat · Projects

Cash in

Live

4.2L

+18%Pulse · Finance

Outstanding

92K

-12% vs last monthPulse · Finance

Leads in pipeline

Live

27

+5 todaySpark · Sales

Without agent (neutral)

Total team hours

284hrs

no change

Usage

import { StatCard } from "@/components/ui/stat-card";

<StatCard
  label="Active projects"
  value="14"
  trend={{ direction: "up", value: "+3 this month" }}
  agentLabel="Beat · Projects"
  agentColor="beat"
/>

<StatCard
  label="Cash in"
  value="4.2" unit="L"
  trend={{ direction: "up", value: "+18%" }}
  agentColor="pulse"
  live
/>

What's still to build

The eight primitives above cover ~60 % of typical SaaS surface area. Coming next, in priority order:

  • · Select · Checkbox · Radio · Switch — form completion layer
  • · Dialog · Popover · Tooltip · Toast — overlay layer
  • · Tabs · Breadcrumbs · Pagination — navigation layer
  • · Table — TanStack Table + virtualisation. The most-used surface in an agency tool.
  • · Empty state · Skeleton · Spinner — async / loading layer
  • · Agent message · Activity feed · Project card — agency-specific composites
  • · Command menu (Cmd+K) — power-user navigation