React · Vue · Svelte · Angular
Write the component once.
One behaviour core, one stylesheet, and thin adapters for four frameworks. Accessible by construction — focus traps, keyboard navigation and ARIA are written once and shared, not reimplemented as each framework's own copy.
Live
These are the real components.
Rendered from @crosskit-ui/react on this page. The other three adapters emit identical markup, so they look identical too.
Every element here carries data-scope and data-part instead of utility classes — which is why one stylesheet can serve four frameworks.
One API
Same props. Every framework.
Prop names are identical everywhere. Only the binding syntax is idiomatic to each framework.
import { Button } from "@crosskit-ui/react";
import "@crosskit-ui/styles";
export function Save() {
return (
<Button variant="primary" icon="check" onClick={save}>
Save changes
</Button>
);
}<script setup lang="ts">
import { Button } from "@crosskit-ui/vue";
import "@crosskit-ui/styles";
</script>
<template>
<Button variant="primary" icon="check" @click="save">
Save changes
</Button>
</template><script lang="ts">
import { Button } from "@crosskit-ui/svelte";
import "@crosskit-ui/styles";
</script>
<Button variant="primary" icon="check" onclick={save}>
Save changes
</Button>import { CkButton } from "@crosskit-ui/angular";
// angular.json -> styles: ["@crosskit-ui/styles"]
@Component({
imports: [CkButton],
template: `
<button ckButton variant="primary" icon="check" (click)="save()">
Save changes
</button>
`,
})
export class SaveComponent {}Accessibility
Focus traps you didn't have to write.
Behaviour lives in one framework-free core — the same tested implementation in all four adapters, instead of four chances to get it wrong.
Theming
Retheme with CSS variables.
Around 48 semantic tokens. Override them in a stylesheet loaded after ours — no rebuild, no fork, and no Tailwind required to consume it.
Built to stay honest.
No utility classes
Components emit data-scope anddata-part, never class strings. One stylesheet serves every framework, and your own CSS still wins.
Tailwind optional
The CSS ships precompiled. Tailwind is our build-time dependency, not yours. Use it if you like — an opt-in bridge maps our tokens onto your utilities.
Dark mode, once
Flip data-theme on html. No dark: variant repeated inside every component.
Install
Two lines.
pnpm add @crosskit-ui/react # or /vue, /svelte, /angular
// then, once, anywhere in your app:
import "@crosskit-ui/styles";Requires React 19, Vue 3.5, Svelte 5 or Angular 20+. ESM only. MIT licensed.