html★ is a client-side library — it doesn't render HTML on the server. But html★ backends that use web components need a way to expand <product-card> into real HTML server-side. A component registry solves this.

The Problem

You write your UI with custom elements:

On the client, the Custom Element definition renders this into real HTML. But on the server — for initial page loads, for html★ fragments, for no-JS users — the tag is empty. You need server-side rendering.

The Registry Pattern

A component registry maps tag names to render functions:

Implementation Options

You don't need to build a registry from scratch. Several libraries handle server-side custom element rendering:

Option 1: enhance-ssr

The @enhance/ssr package is a standalone SSR engine for web components. No framework lock-in — it's a single npm package:

Option 2: Lit SSR

If you use Lit for your client-side components, @lit-labs/ssr can render them server-side:

Option 3: Minimal Custom (Recommended for small projects)

For small projects, a 50-line registry is all you need. The render functions are just template literals — no library required.

Best Practices

  1. Keep render functions pure. They take data in, return HTML out. No side effects, no database calls.

  2. Match client and server output. The server-rendered HTML should match what the client-side Custom Element produces. This prevents content flash when components upgrade.

  3. Use light DOM. Render into the custom element's light DOM (not shadow DOM) so the HTML is visible without JavaScript and html★ can swap it.

  4. Progressive enhancement. Server renders the readable HTML. Client-side Custom Element adds interactivity (event handlers, animations, etc.) without replacing the content.