Teseria

Docs

From the library to your app.

Teseria isn't a package you install. Each element is a pair of source files you drop into your project and own from then on: rename it, restyle it, take it apart. These are the few things every element has in common.

Plain React

Client components for React 19, with no provider to wrap and no runtime of ours.

Two shared packages

Springs come from framer-motion and icons from lucide-react. The Install step lists what each one needs.

One tokens file

Every color, corner and font comes from tokens.css, which you add once.

Add an element

Open any element and switch its sheet to Code. It walks you through three steps:

  1. Install gives the one npm i line for the packages the element imports. Run it once; most elements share the same two.
  2. Files holds the component, its stylesheet and tokens.css. Keep the component and its CSS side by side, in a folder of their own if you like. tokens.css is the same for every element, so you only ever add it once.
  3. Usage is a ready import you can paste and render.

Some elements also come as a registry item, and their Install step opens with an npx shadcn@latest add line that writes the files for you.

Settings.tsx
import { Switch } from "./switch/Switch";
import "./switch/Switch.css";
import "./tokens.css"; // once, anywhere above your elements

export function Settings() {
  return <Switch label="Email me updates" defaultChecked />;
}

Props are typed at the top of each component. Every one has a default, so an element renders with none, and you add only the ones you want to change. Elements that show pictures default to Teseria's demo art, which only exists on this site: pass your own images through their props.

Next.js and friends

Colors and dark mode

No element hard-codes a color. They all read a small set of variables, every one prefixed --ts- so it can't clash with names you already have. Keep the defaults in tokens.css, or point the names at your own theme:

theme.css
/* your theme already has these; point Teseria's names at them */
:root {
  --ts-accent: var(--brand);
  --ts-font: var(--font-sans);
  --ts-page: var(--background);
  --ts-fg: var(--foreground);
}
Surfaces
--ts-page the ground, --ts-raised cards and popovers, --ts-sunken wells and tracks, --ts-tint-1 to -3 neutral fills from light to deep
Text
--ts-fg down through -secondary, -tertiary, -muted and -faint; --ts-fg-inverse for text on an fg fill; --ts-fg-rgb as bare numbers for washes like rgba(var(--ts-fg-rgb), 0.08)
Lines
--ts-border for hairlines, --ts-edge the soft shadow a filled surface wears instead of an outline
Signals
--ts-accent, --ts-focus, --ts-success, --ts-warning, --ts-danger

Dark mode

Light is the default. Put data-theme="dark" on any ancestor to switch an element, or leave it and the element follows the visitor's system setting; data-theme="light" pins it to light. If your app toggles dark mode with a class instead, redefine the same variables under that class.

Corners and type

Controls such as buttons, chips and inputs are always pills. Everything else takes one of three radii, so a whole screen can be squared off or softened from one place:

Type comes from --ts-font. Its default is Inter, falling back to the system sans.

Sound

Teseria's sounds aren't audio files. One TypeScript file, sound.ts, synthesizes each one with the Web Audio API the moment it plays, with no dependencies and nothing to download. Elements never play sound on their own. One that has something worth hearing takes an onSound prop and calls it with a cue name; you choose whether it plays.

sound.tsx
import { play } from "./sound";

// an element names the moment; you decide what plays
<Switch label="Sounds" onSound={(cue) => play(cue)} />

// or call it from your own code, after a click, tap or key press
play("done");
play("push", { at: 0.7 });  // at: 0..1, a little lower or higher
play("key", { gap: 40 });   // gap: skip repeats closer than 40 ms

Hear every cue, and see which elements play it, on the Sounds page; any of them can also be saved as a WAV. The free engine covers the soft voice and every sound the free elements make. Pro adds the other voices and the hand-made sounds.

Your AI editor

Teseria runs an MCP server, so an agent in your editor can search the library and write an element straight into your project. Ask in plain words: "add Teseria's switch to the settings page" or "play a sound when this form saves".

  1. Sign in and open Connect MCP. Make a token there: it's shown once, so copy it before you close the dialog.
  2. Pick your editor in the same dialog for its ready-made setup. It covers Claude Code, Cursor, VS Code, Windsurf, Codex, Gemini CLI and Grok.
Terminal
claude mcp add --transport http teseria https://teseria.dev/api/mcp --header "Authorization: Bearer <your token>"

The server answers four tools: search_elements, get_element, get_sound_engine and about_teseria. Free elements and the free sound engine come back with or without a token. With a Pro token, Pro elements and every sound come back too. Making a new token replaces the old one, so a leaked token is one click from useless.

Accessibility

Every element works from the keyboard and announces itself to screen readers, shows a focus ring when it's reached with Tab, and calms its motion when the system asks for reduced motion. If you restyle one, keep those three: the focus ring reads --ts-focus, and the motion checks live inside the component.

Pro and the license

Free elements and sounds, with their code, are yours to use in personal and commercial work, client projects included. Pro elements show their preview and code once you have a plan, Yearly or Lifetime: see Pricing. On any plan you can ship elements inside your own products, but you can't resell or republish them as a kit, template or library. The full terms are in the license.

Help

Something broken, unclear or missing? Pick Feedback from the menu at the top right of any page, or write to [email protected]. Say which element, and paste the error if there is one.