Primitives

Primitives are the atomic building blocks of the system. Each one owns its own appearance via @scope, reads colour from theme tokens, and can be composed into any shape across any interface boundary.

6 primitives. 22 interfaces. 30 shapes. 4 themes. The model scales.

The 6 primitives

Each primitive names itself with data-primitive, owns its own scoped CSS, and reads colour from the nearest data-theme ancestor. Shapes position primitives; primitives style themselves.

Avatar 3 sizes
AW
sm
AW
md
AW
lg
HTML
<span data-primitive="avatar" data-size="md">AW</span>
Badge
Admin Member Info
HTML
<span data-primitive="badge">Admin</span>
Timestamp 2 sizes
sm — 0.6875rem
md — 0.75rem
HTML
<time data-primitive="timestamp" data-size="sm">3 hours ago</time>
ColorDot 5 colours
interface
shape
ink
white
green
HTML
<span data-primitive="colordot" data-color="interface"></span>
NumberCircle 3 colours
1
interface
2
shape
3
ink
HTML
<span data-primitive="number-circle" data-color="interface">1</span>
BackLink
HTML
<a data-primitive="backlink" href="/">← Back to Intershapes</a>

The primitive contract

Every primitive follows three rules. These rules keep primitives portable, predictable, and composable across any shape or interface boundary.

1
Self-styling via @scope

Each primitive owns its appearance through @scope([data-primitive="..."]). It never relies on parent shape CSS. The shape positions the primitive; the primitive styles itself.

2
Predictable sizing via data attributes

Primitives use data-size, data-gap, and other data attributes — not class names. Each attribute has a finite set of named values, making the API explicit and exhaustive.

3
No parent layout assumptions

Each primitive sets its own display mode and dimensions. It works the same whether it's inside a flex row, a grid cell, or a standalone block. Shapes position primitives; primitives never assume how they're positioned.

These three rules make primitives truly portable. A primitive written for one shape works in any shape, across any interface boundary, without modification. The system grows by adding shapes and interfaces — not by duplicating or customising primitives.

Notification shapes

A third interface domain. Two new shapes composed entirely from existing primitives — no new atoms needed. Badge and Timestamp are reused across interface boundaries.

Interface — Notification
interface Notification {
  title: string
  body: string
  timestamp: string
  type?: "info" | "success" | "warning" | "error"
}

notification-card × 4 themes

Uses Badge (type label) + Timestamp. Left border accent reads from status tokens. Same shape, swap the wrapper.

light
Success

Deployment complete

Production build v2.4.1 deployed successfully to all regions.

dark
Success

Deployment complete

Production build v2.4.1 deployed successfully to all regions.

brand
Success

Deployment complete

Production build v2.4.1 deployed successfully to all regions.

elevated
Success

Deployment complete

Production build v2.4.1 deployed successfully to all regions.

notification-row × 4 themes

Compact horizontal layout. Uses Timestamp. Type indicator via ::before pseudo-element — no extra DOM, no child selector.

light

Build started

CI pipeline triggered for main branch.

Tests passed

All 847 tests passing.

Disk space low

Server us-east-1 at 92% capacity.

dark

Build started

CI pipeline triggered for main branch.

Tests passed

All 847 tests passing.

Disk space low

Server us-east-1 at 92% capacity.

brand

Build started

CI pipeline triggered for main branch.

Tests passed

All 847 tests passing.

Disk space low

Server us-east-1 at 92% capacity.

elevated

Build started

CI pipeline triggered for main branch.

Tests passed

All 847 tests passing.

Disk space low

Server us-east-1 at 92% capacity.

notification-card HTML
<article data-shape="notification-card" data-type="success">
  <div>
    <span data-primitive="badge">Success</span>
    <time data-primitive="timestamp" data-size="sm">5 min ago</time>
  </div>
  <h3>Deployment complete</h3>
  <p>Production build v2.4.1 deployed successfully.</p>
</article>
notification-row HTML
<div data-shape="notification-row" data-type="info">
  <div>
    <h3>Build started</h3>
    <p>CI pipeline triggered for main branch.</p>
  </div>
  <time data-primitive="timestamp" data-size="sm">2m ago</time>
</div>

Type variants

The data-type attribute drives visual differentiation via status tokens. The shape reads var(--status-*) — the theme sets the actual colour. 4 types × 4 themes = 16 visual outputs from 1 shape definition.

info
Info

New comment

Sarah Kim replied to your post.

success
Success

Deployment complete

v2.4.1 deployed to all regions.

warning
Warning

Rate limit approaching

API usage at 90% of quota.

error
Error

Build failed

Test suite failed with 3 errors.

info + dark
Info

New comment

Sarah Kim replied to your post.

success + dark
Success

Deployment complete

v2.4.1 deployed to all regions.

warning + dark
Warning

Rate limit approaching

API usage at 90% of quota.

error + dark
Error

Build failed

Test suite failed with 3 errors.

Cross-domain reuse

Timestamp appears in all 3 interface domains. Same primitive, same scoped CSS, same theme token. Primitives compose across interface boundaries without duplication.

UserProfile profile-horizontal
AW

Alan White

Admin
Comment comment-thread
SK Sarah Kim

Primitives compose across interface boundaries.

Notification notification-card
Info

New follower

Marcus Jones started following you.

What this proves: The Timestamp primitive is defined once, scoped once, themed once — and reused across profile, comment, and notification shapes. Adding a new interface domain required zero new primitives. The model doesn't collapse under its own weight — it gets more efficient as the system grows.

System inventory

6
Primitives
Avatar · Badge · Timestamp
ColorDot · NumberCircle · BackLink
22
Interfaces
Stable contracts across the system
30
Shapes
Visual expressions of those contracts

30 shapes × 4 themes = 120 visual outputs from 32 definitions (6 primitives + 22 interfaces + 4 themes). Primitives compose across interface boundaries without duplication. Adding a new interface domain requires zero new primitives. This is how a design system should scale.