DEV Community

Hedzer Ferwerda
Hedzer Ferwerda

Posted on

I built 130+ web components for myself. Now they're free for everyone.

I'm a big fan of Lit and Shoelace (I've even donated to Shoelace — seriously, go check it out if you haven't — and consider donating to them, I have). They just didn't cover everything I needed for my projects, so I started building my own.

What started as a handful of components turned into Snice — a web component framework and a library of 130+ components built with it. The framework handles rendering, reactivity, styling, event handling, and routing — but everything is modular. You pick what you need. Just want the components? Use those by themselves. Just want the rendering engine? Go for it. Don't need routing? Don't import it. The components are what I built on top of it for my own projects.

Both are free, MIT licensed, no commercial agenda. Just sharing what I needed.

The framework

Snice is built on TC39 standard decorators — the ones actually shipping in TypeScript 5.0+ and browsers, not the legacy experimental ones. Components extend HTMLElement directly, no base class required.

import { element, property, render, styles, html, css } from 'snice';

@element('user-card')
class UserCard extends HTMLElement {
  @property() name = '';
  @property() role = '';

  @render()
  template() {
    return html`
      <div class="card">
        <h3>${this.name}</h3>
        <span>${this.role}</span>
      </div>
    `;
  }

  @styles()
  css() {
    return css`:host { display: block; padding: 1rem; }`;
  }
}
Enter fullscreen mode Exit fullscreen mode

The @render decorator sets up differential rendering — it patches only the DOM nodes that actually changed. No virtual DOM.

The full decorator API:

  • @element('tag-name') — registers a custom element
  • @property() — reactive properties synced with HTML attributes
  • @render() — differential rendering with html tagged templates
  • @styles() — scoped CSS via Shadow DOM
  • @on('click', '.btn') — declarative event handling
  • @request / @respond — async generator-based component communication
  • @context — router-aware context sharing

For full apps, there's built-in hash/pushstate routing with @page, @layout, and @controller decorators. No external router needed.

The components

130+ components built with the framework above. The range goes from everyday UI (buttons, inputs, modals, tabs) to things you'd normally need separate libraries for (data tables, charts, kanban boards, a terminal emulator).

Here's the bird's eye view:

All 130+ Snice components

Every component supports light and dark mode, CSS custom property theming, and works as a single HTML element — no framework required.

Categories

Everyday UI: Button, input, select, checkbox, radio, switch, slider, tabs, accordion, modal, drawer, toast, tooltip, popover, badge, avatar, breadcrumbs, pagination, stepper, skeleton...

Data visualization: Charts, sparklines, gauges, heatmaps, treemaps, candlestick, sankey, waterfall

Project tools: Gantt charts, kanban boards, timelines, approval flows, activity feeds

Rich data: Spreadsheets, data tables with sorting/filtering/pagination, org charts

Media: Music player, video player, camera, audio recorder, PDF viewer

Utilities: QR code generator/reader, color picker, terminal emulator, markdown renderer, code block with syntax highlighting

Use it anywhere

Use the framework to build your own components, use the pre-built ones, or both. Each piece stands on its own — there's no all-or-nothing buy-in.

Drop a script tag — no bundler needed:

<script src="https://cdn.snice.dev/runtime/snice-runtime.min.js"></script>
<script src="https://cdn.snice.dev/components/snice-button.min.js"></script>

<snice-button variant="primary">Click me</snice-button>
Enter fullscreen mode Exit fullscreen mode

Or install via npm:

npm install snice
Enter fullscreen mode Exit fullscreen mode

Works with React, Vue, Angular, Svelte, Astro, plain HTML — anything that renders to the DOM.

There's no paid tier, no pro plan, no upsell. I built these for my own projects and I'm sharing them because the web component ecosystem can always use more options.

I'd love to hear what you think — what's useful, what's missing, what could be better. Keep it constructive.

Top comments (0)