Kishore Kanthan

Ward

A React 19 component library for my apps. One shared file sets its colours, spacing and type. Each change must pass contrast, keyboard and clean install checks.

Ward theme presets: the same controls in green, blue, violet, orange and rose, light and dark.
A sample board page called Shipments, built from Ward layout parts. It has five lanes: Intake, Triage, Build, Review and Release. The Review lane is shaded amber and has a Gate label.

What it is

Ward holds the shared screen parts that my web apps are built from. It started as the user interface of Trellis. In September 2026 it moved to its own public repository. An app installs one package and imports every part from it. It has four kinds of parts:

  • Small parts: buttons, text fields, menus, tabs, switches and a grid for tables.
  • Layout: the frame, sidebar and grids that every page sits in.
  • Larger parts: whole app areas built from the small parts, such as a task board and an intake form.
  • Helpers: keyboard focus hooks, time and count formatters, and parts that show live data.

Ward never imports app code, so a change in an app cannot break it.

One design decision

A design token is a named value, such as a colour or a spacing size. Ward defines every colour, spacing step, type size and breakpoint once, in tokens.json. A script generates the CSS variables and the TypeScript from that file. So one change there updates every component and every theme.

Component CSS may not hold a hex colour or a pixel size, except a 1px hairline. Every breakpoint in component CSS must match the token scale.

The themes come from the same file. Ward has light and dark themes, five accent colours and a compact mode that fits more on screen. An app picks them with ThemeProvider. The generated CSS also stops the animations when a user turns on reduced motion.

How it stays reliable

Every change must pass make check, and CI runs it on every pull request. These are some of its checks:

  • Generated files are current. The generated CSS, TypeScript and built package must match a fresh build exactly.
  • Contrast. Normal text must reach the WCAG AA ratio of 4.5:1. Large text and graphics must reach 3:1. This holds in both themes and with every accent. The check also opens each component example in a browser and measures the contrast of its text.
  • Keyboard and target size. A script tabs through every component example in both themes. Each control must show a clear focus outline. Small links must also be at least 24 px across, so they are easy to click or tap.
  • Layout. A test measures each layout at widths such as 320, 375 and 1280 px. It fails if the result differs from the saved measurements.
  • Code complexity. TypeScript runs in strict mode. The linter fails any function in the library source with a complexity score over 5.

The last part of make check is a consumer test. It packs Ward and installs it into a new, empty app. Then it renders that app on the server and builds it for production. So it finds problems that only appear when another app installs Ward.

How releases work

Since version 0.18.1, a release is a version bump, a passing make check and a signed tag. CI checks the signature of each new tag. A daily job checks the signed tags again. It also makes sure the 26 older, unsigned tags have not moved.

Trellis installs the exact commit of a release, not its tag name. A tag name can be moved to other code, but a commit cannot change. So Trellis always gets the code that passed the checks.

Where it is now

Most changes ship as their own tagged release, and Ward has had more than 130 since September 2026. Trellis builds its screens from its components, plus a local stylesheet for its own layouts. This site loads its stylesheet and uses its token names, with its own colours and type.

On the roadmap: a check that the menus work in Safari with a keyboard and the VoiceOver screen reader.