Learning project · Frontend R&D
Blog Bits
A small-scale CMS I built to sharpen my frontend — and to test a hunch: that a Shadow-DOM component library plus targeted React islands can replace React where it isn't earning its weight.
Overview
A CMS as a frontend proving ground
Blog Bits started as a way to refine my frontend skills on something real: a small content-management system. But the goal underneath was architectural — to see how far you can get with plain Web Components and the Shadow DOM before reaching for a full framework.
The result is a lightweight UI library that handles the static-and-structural work, with islands of micro React apps dropped in only where genuine interactivity earns it — for example, an embeddable chat widget that can live inside an HTMX page or another Shadow-DOM-based site.
Architecture
Server-driven, hydrated only where needed
The CMS renders server-driven HTML enhanced with HTMX. Reusable pieces are Shadow-DOM components with fully scoped styles. Only the genuinely interactive pockets — a chat widget, a rich editor — are hydrated as small React islands, so the JavaScript you ship maps to the interactivity you actually use.
Reach for React last, not first — the library and HTMX carry most of the UI, islands cover the rest.
Only the genuinely interactive pockets (the accented boxes) become React "islands" — the rest of the page ships zero framework code.
Sample UI experience
Content editor
A representative view — a mostly server-rendered admin where only the toolbar and chat are React, each isolated in its own island.
Engineering challenges
What was hard, and what I learned
Where to draw the hydration boundary
ProblemIslands architecture only pays off if the seam between server-rendered and interactive is drawn well — too coarse and you ship a framework for static content; too fine and the page fragments into dozens of tiny runtimes.
ApproachMake interactivity the unit of decision: a region becomes an island only when it owns real client state, and everything else stays server-rendered.
Island state vs. server-driven swaps
ProblemHTMX replaces regions of the DOM from the server, while an island holds its own in-memory state. Reconciling two sources of truth over the same page is the core logical problem.
ApproachGive islands stable identity and a defined lifecycle tied to HTMX's swap events, so ownership of each region is unambiguous at any moment.
A stable component contract
ProblemA reusable library lives or dies by its API. Components need a predictable contract — inputs, events, composition — that doesn't leak their internals to consumers.
ApproachTreat each Web Component as a black box with a declared attribute/event interface, so pages compose against a contract rather than an implementation.
Keeping React off the critical path
ProblemThe whole premise fails if React ends up in the base bundle — then every page pays for a framework most of them don't use.
ApproachIsolate React into per-island bundles loaded only when that island mounts, keeping the default page's dependency graph free of it entirely.