Skip to content

About

Why it exists

Abilian builds and maintains a range of business applications. They share a server stack and share nothing visually: each one accumulated its own Bootstrap fork, its own spacing habits, its own idea of what a "card" is. The cost is not aesthetic. It is that a fix in one is a fix in one, and a developer moving between them starts over.

The usual answer is to adopt an off-the-shelf kit. The usual result is that the kit's opinions leak into the product and its 300 independent values cannot be retuned as a set — so "make it denser for this client" becomes a fork.

The position

Tabler provides the taste; we provide the implementation.

Tabler is a mature, well-proportioned admin design language, and reproducing its judgement is cheaper than inventing one. But consuming it means inheriting Bootstrap, a build step, and a vocabulary nobody here controls.

So this is not a Tabler wrapper. It is an independent implementation, held to Tabler's measurements by a calibration harness that renders 78 elements side by side against the real thing and compares them property by property. It reports zero differences.

That separation is the whole point. Tabler decides how it looks; we decide how it is built. When the two goals diverge — and they do, on accessibility — we can take the divergence deliberately instead of forking.

Where the reference is not enough

Tabler's success green measures 2.48:1 as text on its own tint. The floor for body text is 4.5:1. Rather than silently ship the failure or silently diverge, that became a knob: --ads-contrast: 0 is the reference's own palette, 1 moves every intent to a readable ink without touching a single fill, border or tint. Both ends are asserted by tests.

Where it stands

Usable, in use by the demo application, and proven once against applications it did not grow around — seven of situ's own demos, ported with their Python untouched and only their markup rewritten. Four of the seven made the system grow. Not yet used by a production application, which is the next thing that would teach it something.

Stylesheet 16 files, 3,155 lines — no build step, no runtime dependency
Vocabulary 27 knobs → 128 derived tokens → 264 classes
Demo application 50 routes + 7 inherited from situ · 4 shell layouts · 6 languages · RTL
Visual parity 0 properties differ across 78 elements measured against Tabler
Linter 22 rules, 0 findings
Automated checks 34 library · 25 unit · 40 in a real browser · 1 calibration sweep

What it has been taught

The system is mostly a record of being found wanting, and the four biggest lessons are worth stating because they shape what gets built next.

A colour defined in both themes is not a colour readable in both. Fifty-four contrast failures came from single-valued intent colours the first time anyone rendered a page in dark mode. Every intent now has a fourth shade, -ink, for when it is used as text.

Accessibility claims need conditions, not intentions. Contrast in both themes, reflow at 320px, 200% text-only zoom, keyboard traversal, pointer target size and Windows high contrast are each swept across every route on every run. Every one of them was broken when first measured.

The look must not be able to exist without the meaning. State a person can perceive is an attribute — aria-current, aria-pressed, aria-invalid — and the stylesheet keys off that attribute, so there is nothing for an author to remember. This replaced ten kinds of "current item" that were, to a screen reader, ordinary links.

Two things agreeing with each other is not evidence. abilian-ds tokens --check passed for months against a document describing a design system that had been deleted: the generator read the dead file, the document was its output, and the check compared the two. Every gate here now compares against something that did not move.

What is next

  1. A production application. The ports prove the vocabulary survives someone else's information architecture. They do not prove it survives a deadline, a client's brand, or a developer who has not read any of this. The thing that blocked this — an adopter had to hand-write the application frame — is fixed: sync vendors the shell now.
  2. A real screen reader. Everything tested so far is what a browser can be asked about the DOM, which catches absent semantics and not wrong ones. One known gap: advancing the wizard changes the step and announces nothing.
  3. Density. The knobs sit at Tabler's values so parity can be measured. Abilian's applications are dense tools and may well want a smaller base type and a sub-1 space scale — a decision to take deliberately, once there is a second real consumer to take it against.
  4. Publish the package, so "vendored and hashed" becomes a guarantee rather than a local convention. Unblocked: the install path has been walked from an empty directory — clean virtualenv, wheel, sync, a page on the packaged shell, lint clean — though not yet turned into a test, which is what would make it a guarantee rather than a memory.

Deliberately not on the list: more ported demos. Seven found four gaps. Rebuilding two of them into applications that actually read as a mailbox and an issue tracker found five more, which says the next yield is in depth rather than breadth.

Design principles

These have not changed since the first spec, and they survived the rewrite that deleted almost everything else in it.

  • Tokens are named for intent, not value. --ads-surface is a decision — this is the surface a card sits on. A hex code carries no idea of whether that grey is a card, a hover state or a coincidence.
  • The rules are a check, not a document. If something is off-system and no rule caught it, that is a gap in the rules. No "but the guidelines said not to".
  • Delete the escape hatch, do not discourage it. A person reads the contribution guide once; a model rediscovers the codebase every prompt and takes the path of least resistance. The only way to move the default is to make the wrong thing unavailable.
  • Derive, do not enumerate. If two values must move together, one is computed from the other. A system where --shadow-md and --shadow-lg are independent literals cannot answer "less shadow".
  • Prefer the platform. <details> before a disclosure widget, hidden before a state class, light-dark() before a second stylesheet, :has() before a script.

Licence and credits

Built by Abilian. Visual language after Tabler by Paweł Kuna. Icons are Tabler Icons. Interactive islands use situ. The engineering record is in notes/.