Canon

ALGHATKJ

Component library for internal tools: tables, forms, records.

The markup is the contract.

Pending

Canon builds tables, forms and dialogs once, in plain HTML: the browser does the work, a theme decides the look, and the markup outlives both. Made for the admin screens that Django, Rails, Laravel, Go or htmx already render.

  1. Write it once, keep it

    A <button> written today still works in ten years. Canon is unopinionated about your stack and your look: it's markup, so it works with whatever renders it and outlives the framework of the moment.

  2. Accessible by nature

    This is where Canon is opinionated: names, roles, focus and keys are part of each component's markup. No one has to remember them, and no theme can lose them.

  3. Less JavaScript every year

    Browsers keep doing more on their own. Canon uses what they do, and its script steps back as they catch up.

  4. Works the way you expect

    A table should read like a table, a form should never lose what was typed, and the keyboard should always work.

Who it's for

Canon is for teams with:

A back end and no front-end team
Django, Rails, Laravel and Go templates already write HTML, and that's all Canon needs: two lines in the page, no build step, no client framework.
Several stacks
A React app, a server-rendered admin and an old internal tool write the same elements and attributes, and get the same components.
A brand to follow, or several
One stylesheet decides the look. A rebrand, a client's colors or a new design system is a new theme; the pages stay as they are.
Tools that must last years
Plain HTML has no framework version to keep up with, and a script that fails to load doesn't take the screens with it.

You say what it is. The theme says how it looks.

A button becomes what its attributes say. The theme draws it.

<link rel="stylesheet" href="css/canon/canon.css">

<button type="button" class="canon-button">
  <span class="canon-button-label">Save</span>
</button>

The Components

67 of 68 components work without JavaScript.

Each component's specification gives its tier, from T0 to T3: what it does with HTML and CSS alone, and what canon.js adds. When a script doesn't load, the page still works.

T0 HTML and CSS
49 components
T1 Browser features
7 components
T2 Better with JavaScript
11 components
T3 Needs JavaScript
1 component

What Canon leaves to others, on purpose.

Canon is not:

A JavaScript component library
There's nothing to import or call, and no build step. Your framework or server renders the HTML.
Styled in the markup
Markup says what a thing is (data-intent), never how it looks: no “outline”, “rounded” or “blue”.
An app framework
No routing, data loading or state. canon.js keeps the interface honest; saving and fetching are your app's.
For marketing sites
Tables, forms, records and dashboards. Hero sections and pricing tables are out of scope.

Origins

The name comes from fiction, where canon is the body of work officially accepted as authoritative within a story's universe. Here, the markup is canon. Themes can retell it however they like, but what the markup says stays true in all of them.

In 2003, Dave Shea published CSS Zen Garden: one HTML document, and a gallery of designs that changed nothing but the stylesheet. Each looked like a different site, and the markup never moved.

Canon is an homage to that page. It asks the same of the things internal tools are made of: write a table, a form or a dialog once, then let a theme redraw all of it without touching a line of HTML.

Start

Two lines, then the markup each component's page shows.

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/canon-ui@0.2.1/css/canon/canon.css">
<script src="https://cdn.jsdelivr.net/npm/canon-ui@0.2.1/js/canon.js" defer></script>

Or install it from npm.

npm i canon-ui