<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hedzer Ferwerda</title>
    <description>The latest articles on DEV Community by Hedzer Ferwerda (@hedzer_ferwerda_a9c37a296).</description>
    <link>https://dev.to/hedzer_ferwerda_a9c37a296</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3813278%2F1b3d08b8-e7d7-4d24-858c-39b3184d3c0d.png</url>
      <title>DEV Community: Hedzer Ferwerda</title>
      <link>https://dev.to/hedzer_ferwerda_a9c37a296</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hedzer_ferwerda_a9c37a296"/>
    <language>en</language>
    <item>
      <title>I built 130+ web components for myself. Now they're free for everyone.</title>
      <dc:creator>Hedzer Ferwerda</dc:creator>
      <pubDate>Mon, 09 Mar 2026 16:32:53 +0000</pubDate>
      <link>https://dev.to/hedzer_ferwerda_a9c37a296/i-built-130-web-components-for-myself-now-theyre-free-for-everyone-4olf</link>
      <guid>https://dev.to/hedzer_ferwerda_a9c37a296/i-built-130-web-components-for-myself-now-theyre-free-for-everyone-4olf</guid>
      <description>&lt;p&gt;I'm a big fan of &lt;a href="https://lit.dev/" rel="noopener noreferrer"&gt;Lit&lt;/a&gt; and &lt;a href="https://shoelace.style/" rel="noopener noreferrer"&gt;Shoelace&lt;/a&gt; (I've even donated to Shoelace — seriously, go check it out if you haven't — and consider &lt;a href="https://shoelace.style/" rel="noopener noreferrer"&gt;donating to them&lt;/a&gt;, I have). They just didn't cover everything I needed for my projects, so I started building my own.&lt;/p&gt;

&lt;p&gt;What started as a handful of components turned into &lt;strong&gt;&lt;a href="https://snice.dev" rel="noopener noreferrer"&gt;Snice&lt;/a&gt;&lt;/strong&gt; — a web component framework &lt;em&gt;and&lt;/em&gt; 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.&lt;/p&gt;

&lt;p&gt;Both are free, MIT licensed, no commercial agenda. Just sharing what I needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The framework
&lt;/h2&gt;

&lt;p&gt;Snice is built on TC39 standard decorators — the ones actually shipping in TypeScript 5.0+ and browsers, not the legacy experimental ones. Components extend &lt;code&gt;HTMLElement&lt;/code&gt; directly, no base class required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;snice&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserCard&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;property&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;property&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;template&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
      &amp;lt;div class="card"&amp;gt;
        &amp;lt;h3&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h3&amp;gt;
        &amp;lt;span&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/span&amp;gt;
      &amp;lt;/div&amp;gt;
    `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="s2"&gt;`:host { display: block; padding: 1rem; }`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@render&lt;/code&gt; decorator sets up differential rendering — it patches only the DOM nodes that actually changed. No virtual DOM.&lt;/p&gt;

&lt;p&gt;The full decorator API:&lt;/p&gt;

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

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

&lt;h2&gt;
  
  
  The components
&lt;/h2&gt;

&lt;p&gt;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).&lt;/p&gt;

&lt;p&gt;Here's the bird's eye view:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx973x88cau0hmv3991ik.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx973x88cau0hmv3991ik.png" alt="All 130+ Snice components" width="800" height="908"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every component supports light and dark mode, CSS custom property theming, and works as a single HTML element — no framework required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Categories
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Everyday UI&lt;/strong&gt;: Button, input, select, checkbox, radio, switch, slider, tabs, accordion, modal, drawer, toast, tooltip, popover, badge, avatar, breadcrumbs, pagination, stepper, skeleton...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data visualization&lt;/strong&gt;: Charts, sparklines, gauges, heatmaps, treemaps, candlestick, sankey, waterfall&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project tools&lt;/strong&gt;: Gantt charts, kanban boards, timelines, approval flows, activity feeds&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rich data&lt;/strong&gt;: Spreadsheets, data tables with sorting/filtering/pagination, org charts&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Media&lt;/strong&gt;: Music player, video player, camera, audio recorder, PDF viewer&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Utilities&lt;/strong&gt;: QR code generator/reader, color picker, terminal emulator, markdown renderer, code block with syntax highlighting&lt;/p&gt;

&lt;h2&gt;
  
  
  Use it anywhere
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Drop a script tag — no bundler needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.snice.dev/runtime/snice-runtime.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.snice.dev/components/snice-button.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;snice-button&lt;/span&gt; &lt;span class="na"&gt;variant=&lt;/span&gt;&lt;span class="s"&gt;"primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click me&lt;span class="nt"&gt;&amp;lt;/snice-button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or install via npm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;snice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Works with React, Vue, Angular, Svelte, Astro, plain HTML — anything that renders to the DOM.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live demos&lt;/strong&gt;: &lt;a href="https://snice.dev" rel="noopener noreferrer"&gt;snice.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;npm&lt;/strong&gt;: &lt;a href="https://www.npmjs.com/package/snice" rel="noopener noreferrer"&gt;snice&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source&lt;/strong&gt;: &lt;a href="https://gitlab.com/Hedzer/snice" rel="noopener noreferrer"&gt;GitLab&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;MIT licensed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;I'd love to hear what you think — what's useful, what's missing, what could be better. Keep it constructive.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
