Reactive web components. No build step, no virtual DOM.
nisli is a reactive framework for the native platform — signals, tagged-template components, dependency injection, static rendering. Batteries included: @nisli/ui, a shadcn-style component library you copy in and own.
import { component, signal, html } from '@nisli/core';
const Counter = component('my-counter', () => {
const count = signal(0);
return html`
<button @click=${() => count.value++}>
count is ${count}
</button>
`;
});
A framework, not a library of workarounds
Everything you need to build reactive interfaces on the web platform — compiled to nothing.
Signals
Fine-grained reactivity — signal(), computed(), effect(). No re-renders, no diffing; only what changed updates.
Tagged-template components
Author UI with the html`` tag. No JSX, no compiler, no build step — templates are just JavaScript.
Native custom elements
component() defines a real custom element. Interoperable everywhere, framework-agnostic, no runtime lock-in.
Dependency injection
provide() / inject() with typed tokens. Share services down the tree without prop-drilling or globals.
Declarative data
query() loads async data with caching and loading state, wired straight into the reactivity graph.
Static rendering
@nisli/ssg renders components to static HTML — this very site is nisli, rendered to a static bundle.
A component library you own
@nisli/ui is nisli's design language — shadcn-style components, ported to nisli, copied into your project as source you control. Every component below is real @nisli/ui, rendered to static HTML by @nisli/ssg.
Install the framework, copy in the components
nisli = framework + design language + UI components, all in one. No registry account, no lock-in — the components become your source.
-
1
Install the framework
nisli is the product — signals, components, DI, all in @nisli/core.
npm install @nisli/core -
2
Set up @nisli/ui
One-time init drops the token layer and config into your project.
npx @nisli/ui init -
3
Copy in the components you want
add copies real source into your repo — you own and edit it.
npx @nisli/ui add button dialog
Then import your copy and go:
import { Button } from '@/components/ui/button';
// your owned copy — edit it, it's yours
document.body.append(Button({ children: 'Ship it' }));