🚀 Glint is a fast, build-less native web component-based UI framework that makes reactive web development simple and fun again — All without the virtual DOM, complex hooks, or build tools.
- ✅ No Babel, No JSX, No Webpack
- ✅ Native Web Components & Scoped Styles by Default
- ✅ Fine-Grained Reactivity Without Re-Renders
- ✅ Auto-Batching, No useEffect Hell
- ✅ Built-in State Management, No Context API Needed
💡 Think React, but simpler, faster, and without the bloat.
We need a low-barrier, low-bullshit way of creating and consuming real web components. The DX for native web components kinda sucks... That's why I started work on this.
And please -- steal this idea and make something better... Or contribute.
Glint is still very much a work in progress: Features, APIs, and documentation may be assumed incomplete and are subject to change.
👉 Use something like lit-element
or React
/Preact
if you require production-grade component abstractions.
While we’re actively developing and iterating, please expect breaking changes or inconsistencies between the code and the docs.
In essence... Proceed with EXTREME caution if you need production stability! Glint is conceptually awesome (if I say so myself), but it's not yet ready for prime time -- just remember to check back soon! And please contribute 🙏
Glint runs directly in the browser—no setup required. Check it out on codepen!
For now, you can clone the repo and use the src/index.js
file in your project.
<script type="module" src="path/to/src/index.js"></script>
npm install glint-js
<script type="module" src="https://cdn.jsdelivr.net/npm/glint-js"></script>
import { component, signal, html } from 'glint-js';
component('counter-button', ({ start = 0 }) => {
const count = signal(Number(start));
return html`
<button @click=${() => count(count() + 1)}>
Clicked ${count} times
</button>
`;
});
<counter-button start="5"></counter-button>
// top-level app component
const _App_ = () => html`
<main>
<counter-button start="5" />
</main>
`;
// bootstrap app in entry point
render(_App_, {
autoRegister: true,
rootNode: document.querySelector('#glint-app'),
});
Boom! 💥 Your component just works—no build step, no config, no bullshit.
🔥 Glint aims for a DX similar to React without the headache.
- ✅ No VDOM Overhead → Faster, direct DOM updates.
- ✅ Zero Build Step → Works without Babel/Webpack/Vite.
- ✅ Signals & Computed State → No useEffect boilerplate.
- ✅ Scoped Styles for Free → Just like native components. There's even an escape hatch.
- ✅ Event Binding Like HTML → Just use @click=${fn}.
- ✅ Native Web Standards → No lock-in, just HTML, JS, and CSS.
Feature | React | Glint |
---|---|---|
Build Tools | Required (Babel, Webpack) | 🚀 None (Runs in browser) |
Reactivity | Hooks (useState , useEffect ) |
🚀 Signals & Computed State |
Event Handling | Synthetic Events | 🚀 Native DOM Events (@click=${fn} ) |
Context API | Required for state sharing | 🚀 Global store() (No Prop Drilling) |
Performance | VDOM Reconciliation | 🚀 Direct DOM Updates |
Define components using signals—no hooks needed.
component('my-counter', () => {
const count = signal(0);
return html`
<button @click=${() => count(count() + 1)}>Count: ${count}</button>
`;
});
component('styled-box', () => {
css`
div {
background: purple;
padding: 1em;
color: white;
}
`;
return html`<div>Styled Box</div>`;
});
const doubleCount = computed(() => count() * 2);
component(
'custom-card',
() => html`
<style>
.card {
border: 1px solid #ccc;
padding: 1em;
}
</style>
<div class="card">
<slot name="header"></slot>
<slot></slot>
</div>
`,
);
<custom-card>
<h3 slot="header">Title</h3>
<p>Content here</p>
</custom-card>
const theme = store('dark');
theme('light'); // Updates all subscribers
<button @click=${handleClick}>Click Me</button>
Uses native event listeners, unlike React’s synthetic event system.
DEMO on Codepen
💡 Fun fact: Glint was developed entirely on Codepen... Thanks, Chris Coyer! (:
🚀 Check out the interactive playground:
- 👉 Glint Sandbox (Coming soon!)
Registers a Web Component.
component('hello-world', () => html`<h1>Hello, World!</h1>`);
Creates reactive state.
const count = signal(0);
count(count() + 1);
console.log(count());
//> 1
Creates a derived state variable.
const double = computed(() => count() * 2);
Tagged template for templating.
return html`<button>${count}</button>`;
Global state management.
// NOTE: UNIMPLEMENTED
const user = store({ name: 'Alice' });
git clone https://github.com/toddpress/glint.git
<!-- NOTE: UNIMPLEMENTED -->
<script type="module" src="https://cdn.jsdelivr.net/npm/glint-js"></script>
# NOTE: UNIMPLEMENTED!
npm install glint-js
Then, in your components:
// NOTE: UNIMPLEMENTED
import { component, signal, html } from 'glint-js';
🚀 Want to help shape Glint? Open an issue or submit a PR!
- 👉 GitHub Issues (Coming soon!)
MIT License – Use it freely!
- 🚀 No JSX, No build step, Just Web Components.
- ⚡ No VDOM, only updates what changes.
- 🎨 Scoped styles for free, no extra tooling.
- 🔗 Works anywhere: Use inside React, Vue, Svelte, or vanilla JS.