Skip to content

Interface foundations · v0.1.0

A small system for precise interfaces.

Compact controls, a 4px scale, and hierarchy built from type, space and thin rules. No decoration that does not explain something.

Button / Primary

Height
32 / 44px
Radius
4px
Text
14 / 600
Icon
16px

Getting started

Install

One stylesheet. No package to add, no build step to run.

Link it

The whole system, straight from this site.

<link rel="stylesheet" href="https://greda.design/styles/greda.css">

That entry point imports tokens.css, base.css and components.css. Linking those three directly instead trades four requests in series for three in parallel.

Or copy it

To stay standalone, or to pin a version.

styles/
├── greda.css      entry point, declares the layer order
├── tokens.css     colour, type, space, shape, motion
├── base.css       reset, base elements, utilities
├── components.css every component
└── fonts.css      optional, loads the typefaces

Copy the folder and link /styles/greda.css. A copy never changes under you; it also never picks up a fix, so note which version you took — greda.css carries it in its header.

Typefaces

Optional, and deliberately separate.

<link rel="stylesheet" href="https://greda.design/styles/fonts.css">

Greda declares the type stack but loads no fonts: a stylesheet should not call a third party unasked, and it would break under a strict font-src policy. Skip this and the stack falls back to Helvetica Neue and the platform mono.

Write markup

Every public class is prefixed gr-.

<button class="gr-button gr-button--primary">Save</button>

<label class="gr-field">
  <span class="gr-field__label">Email</span>
  <span class="gr-field__control">
    <input type="email">
  </span>
</label>

Block, __part, --variant. Tokens follow the same shape: --gr-color-text, --gr-space-4.

What it will not do

Two things worth knowing before you link it.

It will not fight your CSS

Everything lives in cascade layers, so any unlayered rule in your project wins without raising specificity and without !important.

It does reduce your animations

The prefers-reduced-motion rule is global, so it quiets the host page's own motion too. That is deliberate, and it is the one thing Greda imposes.

Criteria

Principles

The rules that let you decide before adding a component or a variant.

The scale rules

Spacing starts at 4px. Most internal relationships use 4, 8 or 12px; layout uses 16, 24, 32, 48 and 64px.

Deliberate density

Controls are 32px with a precise pointer and 44px on touch. A compact identity does not give up reach.

Quiet hierarchy

Type, space and alignment first. Borders only where they separate; shadows only where something genuinely floats.

Grow on evidence

A pattern enters the system after repeating itself in real products. Greda does not try to anticipate every possible interface.

Core styles

Foundations

Semantic tokens a project can consume without knowing the primitive values.

color.*
font.sans

Inter does the work.

space.1–8
radius.*

4px for controls · 8px for surfaces

motion.*

150 / 220 / 320ms · transform + opacity

layer.*

sticky 100 · toast 300 · skip 400; native overlays take no z-index

focus.*

2px of accent; offset 3px, or 1px hugging a control that already has a border

theme

Light and dark through light-dark(); no component knows which is active

Primitives

Components

Button, Link, Field, Textarea, Select, Choice, Switch, Card, Badge, Table, Prose, Dialog, Disclosure, Tabs, Popover, Callout, Toast, Spinner, Progress, Skeleton, Empty state, Breadcrumb, Pagination, Header, Nav, Footer and Skip link.

Button

Primary, secondary, quiet and disabled.

Field

Label, help text and visible focus.

Textarea

The same control, aligned to the top and resizable.

Select

Native control; it only borrows the box.

Choice

Checkbox and radio share everything but the shape.

What gets validated

Switch

A physical state: the thumb travels, the track does not animate.

States

Error, required, readonly and disabled.

Card

A surface, not decoration.

Personal project

A surface grouped only when the content needs a boundary you can recognise.

Badge

A short label, in mono like everything technical.

v0.1.0 Stable API change

Table

Rules that separate; numbers in mono and to the right.

ControlCompactTouch
Button32px44px
Field32px44px
Choice20px44px

Prose

For text whose markup you do not control class by class.

The system does not try to anticipate every interface. A pattern enters once it has repeated itself across real projects.

What an addition has to bring

  • Complete interactive states, :focus-visible included.
  • Mobile behaviour from 360px up.
  • Tokens instead of repeated values.

<link rel="stylesheet" href="/styles/greda.css">

Dialog

Native <dialog>: trapped focus and Escape for free.

Discard the changes

Everything edited since the last save will be lost. This cannot be undone.

Disclosure

<details>; the panel does not animate.

Why is there no build step?

Because a person should be able to copy the styles/ folder and keep working without installing anything.

When does a component get in?

Once it has shown up as a real pattern in more than one project.

Tabs

The styling lives here; keeping aria-selected in sync is the consumer's.

32px with a precise pointer, from 45rem up.

Popover

The popover attribute: top layer and light dismiss.

Local references, duplicate ids, inline styles, colours outside the tokens, and transitions on properties that are not composited.

Callout

A message that stays on the page.

Breakpoints are a fixed scale

A media query cannot read a token, so sm, md and lg are written out.

The accent does not separate focus from error

Today danger resolves to the accent; separating them is one line in tokens.css.

Toast

Transient; it lives on the toast layer.

Tokens validated: 2 documents, 7 stylesheets.

In real use it sits inside .gr-toast-region, which pins it to the bottom and intercepts no clicks.

Spinner and Progress

Indeterminate and determinate; the second is <progress>.

Validating tokens…

The spinner never travels alone: prefers-reduced-motion freezes it, and a still circle says nothing. The label does.

Skeleton

Only opacity moves; the block keeps its size.

Empty state

Name what is missing and offer the way out.

No component matches

Try another name, or look at the full list of primitives.

View all

Breadcrumb

The current page is marked with aria-current.

Pagination

44px targets, 32px with a precise pointer.

Header, Nav and Footer

This page's own; they no longer live in docs.css.

The top bar is .gr-header with .gr-nav, and it uses the sticky layer instead of an invented z-index. The footer is .gr-footer.

Skip link

The page's first focus; revealed by keyboard.

Skip to content

It lives at the start of the <body>. Press Tab on load to watch it appear.