Composability & Architecture

Because CellUI components execute exactly once, you don't have to rethink how JavaScript works just to build a UI. CellUI allows you to compose your applications the exact same way you would compose any vanilla JS library.

Small-Scale Composability

At a small scale, composability in CellUI means writing simple, pure functions.

You do not need "Render Props", "Higher Order Components", or complex children APIs. If you want to embed a Component into another Component, you just call it!

Example: A Reusable Card

import { view } from '@cmj/cellui';

// 1. A pure function that takes regular arguments
function Card(title: string, content: Node | DocumentFragment) {
  return view`
    <div class="card">
      <h2 class="card-title">${title}</h2>
      <div class="card-body">
         ${content}
      </div>
    </div>
  `;
}

// 2. Composing it elsewhere
function App() {
  return view`
    <main>
      ${Card("User Profile", UserDetails())}
      ${Card("Settings", SettingsMenu())}
    </main>
  `;
}

Large-Scale Composability (Substrates)

As your application grows—perhaps you are building a dashboard with 100+ components—passing data via function arguments (prop drilling) becomes tedious.

At a large scale, you should compose your application architectures using Substrates.

A Substrate is an isolated dependency-injection container. It allows an entire "tree" of CellUI components to share a decentralized memory layer.

Pattern: The "Feature Module"

Instead of building one monolithic app, break your app into modular "Features" that each manage their own memory Substrate.

import { Substrate, signal, view } from '@cmj/cellui';

// 1. Create an isolated Context for the Dashboard feature
const DashboardContext = new Substrate('analytics-dashboard');

export function AnalyticsDashboard() {
  // 2. The Root component initializes the data into the Substrate
  DashboardContext.infuse('date-range', signal('7D'));
  
  return view`
    <div class="dashboardLayout">
       ${SidebarControls()}
       ${ChartCanvas()}
    </div>
  `;
}

// 3. Deeply nested children extract the data directly
function ChartCanvas() {
  // No props needed! We pull it straight from the closest Substrate layer.
  const dateRange = DashboardContext.extract<string>('date-range');
  
  return view`
    <canvas id="chart">Drawing chart for ${dateRange}...</canvas>
  `;
}