Skip to content

Usage

No build step needed. Add a script tag and start using components:

<script type="module" src="https://unpkg.com/@tessera-ui/core/dist/tessera-ui/tessera-ui.esm.js"></script>
<ts-button variant="primary">Submit</ts-button>
<ts-input label="Email" type="email" placeholder="you@example.com"></ts-input>
<script>
document.querySelector('ts-button').addEventListener('tsClick', () => {
console.log('Button clicked!');
});
document.querySelector('ts-input').addEventListener('tsInput', (e) => {
console.log('Value:', e.detail.value);
});
</script>

Terminal window
npm install @tessera-ui/core
main.js
import '@tessera-ui/core';
<ts-button variant="primary">Submit</ts-button>
<ts-input label="Email" type="email" placeholder="you@example.com"></ts-input>

Terminal window
npm install @tessera-ui/react
import { useState } from 'react';
import { TsButton, TsInput } from '@tessera-ui/react';
function App() {
const [name, setName] = useState('');
return (
<>
<TsInput
label="Name"
placeholder="Enter your name"
value={name}
onTsInput={(e) => setName(e.detail.value)}
/>
<TsButton variant="primary" onTsClick={() => alert(`Hello, ${name}!`)}>
Submit
</TsButton>
</>
);
}

Terminal window
npm install @tessera-ui/vue

Add isCustomElement to your Vite config:

vite.config.js
import vue from '@vitejs/plugin-vue';
export default {
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('ts-'),
},
},
}),
],
};
<template>
<TsInput
label="Name"
placeholder="Enter your name"
:value="name"
@tsInput="name = $event.detail.value"
/>
<TsButton variant="primary" @tsClick="alert(`Hello, ${name}!`)">
Submit
</TsButton>
</template>
<script setup>
import { ref } from 'vue';
import { TsButton, TsInput } from '@tessera-ui/vue';
const name = ref('');
</script>

Terminal window
npm install @tessera-ui/angular
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { DIRECTIVES } from '@tessera-ui/angular';
@Component({
selector: 'app-root',
standalone: true,
imports: [DIRECTIVES],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<ts-input
label="Name"
placeholder="Enter your name"
(tsInput)="onInput($event)"
></ts-input>
<ts-button variant="primary" (tsClick)="onSubmit()">
Submit
</ts-button>
`,
})
export class AppComponent {
name = '';
onInput(e: Event) {
this.name = (e as CustomEvent).detail.value;
}
onSubmit() {
alert(`Hello, ${this.name}!`);
}
}

These patterns work the same way across all frameworks.

Override design tokens with CSS custom properties:

:root {
--ts-color-interactive-primary: #7c3aed;
--ts-button-radius: 9999px;
--ts-font-family-base: 'Nunito', sans-serif;
}
<html data-theme="dark">
// Toggle dynamically
document.documentElement.setAttribute('data-theme', 'dark');
<html data-density="compact"> <!-- tighter spacing -->
<html data-density="spacious"> <!-- more breathing room -->
<ts-card>
<h3 slot="header">Title</h3>
<p>Body content</p>
<div slot="footer">
<ts-button size="sm">Action</ts-button>
</div>
</ts-card>
ts-button::part(base) {
text-transform: uppercase;
}
<html dir="rtl">

All components use CSS logical properties and adapt automatically.