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 interactive pockets (a chat widget, a rich editor) are hydrated as small React islands, so the JavaScript you ship maps to the interactivity you use.
Reach for React last, not first: the library and HTMX carry most of the UI, islands cover the rest.
Only the 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.