Skip to content

Simple components for content sites.

Teasim builds the parts a documentation site actually needs — accessible elements, page-level blocks, and the content pipeline behind them.

Start with a component, or take the whole scaffold.

Render markup, not opinions.
Every element ships behaviour and semantics. The stylesheet stays yours.
Keep the data separate.
Navigation, validation, and routes are computed by a package that renders nothing.
Work without JavaScript first.
The open state belongs to the browser. A runtime binds on top when there is one.

Two packages

Everything that renders, and everything that computes.

Six things they do between them, and a project can take either half on its own.

Elements
Accordion, dialog, menu, table — families that render markup and carry the behaviour with it.
Blocks
Page-level pieces that arrange the elements into a shell, a nav, a pager, a table of contents.
Navigation
createNavigation turns a content collection into a sidebar, breadcrumbs, and prev/next links.
Schemas
A content schema with validation that runs in dev and names the page that is wrong.
Markdown routes
Every page gets a markdown twin, plus llms.txt and llms-full.txt for machines.
Scaffolding
astra create generates the routes, layouts, and config — by importing the packages, never vendoring them.

Preview

Every element is the markup you would have written.

Nothing here is a wrapper around a widget. The disclosure below is a details element, and the variants beside it are class strings a recipe named.

Accordion

Open one and the others close.

The name attribute does that, not a script. Arrow-key roving is what the runtime adds on top.

Does this need JavaScript?

No. The disclosure is the browser's, and so is the exclusive-group behaviour when items share a name.

Where do the styles come from?

Your application's TeaCSS build. The package ships no stylesheet.

Variants

One recipe, one contract.

Every family names its variants the same way, so a button, a badge and an alert answer to the same words.

DefaultPrimaryInfoSuccessWarningError

Getting started

Install them, then point them at your content.

This site is built with the three packages it documents. The sidebar on every reference page is computed by createNavigation from @teasim/astra; the chrome around it comes from @teasim/aster, and every surface inside it from @teasim/astro.

npm install @teasim/astro @teasim/aster @teasim/astra

The three packages

The split is what they produce, not how big they are:

Package What it gives you
@teasim/astro The elements — 77 families that render markup and carry their behaviour. No stylesheet
@teasim/aster The blocks — 15 page-level pieces that arrange those elements into a site’s chrome
@teasim/astra Everything that computes — navigation, schemas, validation, and the machine-readable routes

Read Project structure for what a scaffolded project contains and where the boundary falls, Accordion for what an element page looks like, and createNavigation for the data layer underneath all of it.

Built for agents too

Every page here has a markdown twin. Append .md to any address, or start from the index the integration generates:

None of it is hand-maintained. astra() derives all three from the same entries the sidebar is built from, so the corpus can never list a page the site does not serve.

A note

Why the split is the whole idea.

A component library that ships a stylesheet decides how your site looks. A content helper that renders markup decides how your site is built. Both are borrowed decisions, and both are expensive to undo later.

So the packages are split along that line. @teasim/astro renders markup and carries behaviour with it, @teasim/aster arranges those elements into a site's chrome, and @teasim/astra computes navigation, validates content, and serves the machine-readable routes. None of them knows what the others look like.

Teasim

@teasim/astro · @teasim/aster · @teasim/astra

Notes

What we learned building this.

Working notes on the decisions, the measurements, and the things that turned out to be wrong.