A framework-independent design system. The components are CSS classes and web components, things the browser already understands. Whether the team uses React, Astro, Datastar or plain HTML, it is the same system and the same API.

A design system tied to one framework has to be rewritten when the framework is replaced. The browser's own APIs are not replaced.

LO-TEK grade

  1. Reads on any screen.
  2. Survives any patch.
  3. Says when it’s broken.
Package
@lo-tek/interfaces
Status
Before 1.0. Breaking changes are in the changelog.
Licence
MIT
Source
github.com/MarkusAugust/lo-tek
Figure 1-1 · Interface unit, exploded view A is the theme, the bezel that gives the face its colours and lifts off without the panel under it noticing. C is the chassis and B the panel: the markup, which stands there whatever happens. D is the web component, a card that pulls out and goes back without the rest noticing. E brings the page in from the server. F are the screws: the web standards, a thread that fits every frame.

The Halcyon board asked Trace what it runs on.

“Whatever sends the page. Whatever shows it. Nothing in between.”

“So it needs a framework?”

“It doesn’t need anything. Bring yours.”

Trace, LO-TEK Interfaces

Architecture

  1. css

    A class on a plain HTML element. No JavaScript is loaded, and variants are set with data attributes. A button costs one class.

    <button class="lt-button">
    • Button
    • Field
    • Table
    • Card
  2. frame

    You write the HTML. The web component fills in the wiring where it is missing, adds keyboard handling and focus, and leaves the elements in the plain DOM.

    <lt-field>…</lt-field>
    • Field
    • Tabs
    • Dialog
    • Suggestion
  3. standalone

    The web component creates all of its content itself, because there is nothing for the server to send. A server that is gone cannot report it.

    <lt-connection-status>
    • Connection status
    • Toast

The whole reasoning, and the answer to when you use the builder function rather than the web component, is in Markup and behaviour.

What you do not have to solve yourself

  1. The editor knows the components

    Write data-variant="secundary" by hand and nothing happens: the button keeps the default style, and the browser says nothing. Write it through the function and you get an error in the editor before you can save.

    <button
      {...lt.button({
        variant: "secondary",
      })}
    >
      Save draft
    </button>

    The function returns a plain object of attributes, so the same call works in JSX, in an Astro template and in plain JavaScript. If you write HTML without TypeScript, the VS Code extension does the same, and JetBrains gets completion from the package itself.

  2. Your CSS beats ours

    All our CSS sits in its own cascade layer. An ordinary rule in your own CSS then beats ours, however specific ours is, and without !important. If you only want to change shape or size, there is a variable per component.

    :root {
      --lt-button-radius: 9999px;
    }

    The tests open a browser and check that your rule actually wins, that the variable comes through, and that a Tailwind utility beats the component's own value.

  3. The colours meet the contrast requirement

    Every colour pair in the system is computed and checked against the WCAG requirement, in both light and dark themes. If you give your own brand colours, their families are computed afresh with buildTheme.

    const theme = buildTheme({
      accent: "#0062ba",
    })
    
    // theme.violations is empty
    // when the contrast holds

    The colours are computed in OKLCH, because lightness in HSL means something different for each hue. The brand colour gives the hue, while the role sets the lightness and how much of the chroma is kept. Every page here is run through axe in both themes.

  4. The coding agent does not have to guess

    An agent that does not know the design system invents lt-modal, hard-codes the colours and writes its own CSS when the stylesheet is missing. LO-TEK has a rulebook for agents per framework, and it ships with the package. When the agent is done, the check says what is wrong, with file and line.

    npx @lo-tek/interfaces check form.html
    
    form.html:3:13: warning: The class "lt-modal"
      does not exist in LO-TEK.

    The whole documentation also exists as Markdown, made from the same pages you are reading now, and llms.txt shows the way. More about the setup under Coding agents.

The film

LO-TEK: Nothing In Between. One unbroken flight inwards through a machine drawn in white ink on dark paper, from a tower in the rain down through server halls, circuit boards, hard drives and a picture tube to single atoms. The machines come apart in time with the music, and the film ends on a small screen with a page that is still loading. With English captions.