DEV Community

Cover image for HTML-First:Why I Built My Own HTML-First Multi-Part Application Architecture (And You Might Want To Too)
yaniv soussana
yaniv soussana

Posted on • Edited on

HTML-First:Why I Built My Own HTML-First Multi-Part Application Architecture (And You Might Want To Too)

Building modern web apps often means choosing between SPAs or traditional MPAs. I wanted a simpler, faster, and more flexible approach that keeps HTML as the source of truth, allows mixing server-rendered and client-only components, and avoids JSX entirely. In this article, I’ll walk you through my HTML-First Multi-Part Application architecture, why I built it, and how it can boost performance and maintainability for your projects.

Motivation

I decided to create my own HTML-First architecture to build something easy, robust, and performance-oriented. By leveraging Sigment’s syntax (e.g., return div("hello")), components are declared in plain JavaScript without JSX. This produces smaller bundles, faster performance, and a simpler development experience.

Why Not a SPA?

While SPAs are powerful, they aren’t always ideal for larger projects. My Multi-Part Application (MPA) approach allows parts of a page to be server-side rendered (SSR) for SEO, while other parts can remain client-rendered when SEO isn’t critical. This combination provides better SEO, fine-grained performance optimization, and flexibility in choosing which parts of a page require SSR.

Architecture & Concepts

My MPA differs from traditional MPAs because a single page can contain multiple independent parts, each with its own components and lifecycle. Key concepts include:

  • <layout>: Base template for a page containing data-part placeholders.
  • data-part: Marks sections in the layout that can be overridden by page-specific content.
  • data-component: Represents interactive or dynamic components that can be SSR (runAtServer) or client-only.
  • data-paramname: Allows sending parameters to a component. Example: <div data-component="Product" data-item="laptop"></div> Inside the component (client-only), you can access it via props.item. ⚠️ Works only for client-only components, not SSR.

This system allows mixing SSR and client-only components seamlessly on the same page.

Layout Example

Here’s an example of a layout file:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My Site</title>
  <meta name="description" content="">
  <meta name="keywords" content="">
  <link rel="stylesheet" href="/assets/css/index.css">
</head>
<body>
  <header>
    <div data-component="Header" runAtServer></div>
  </header>

  <main>
    <div data-part="sectionA"></div>
    <div data-part="sectionB"></div>
    <div data-part="sectionC"></div>
  </main>

  <footer>
    <div data-component="Footer" runAtServer></div>
  </footer>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Example of Using Layout in a Page

<layout data-layout="/layouts/index.html"></layout>
<description data-description="Hello page description"></description>
<keywords data-keywords="hello,greeting"></keywords>
<script type="module" src="/bundle.js"></script>

<div data-part="sectionA">
  <h1>Hello Page</h1>
  <p>This page shows the Hello component.</p>
  <div data-component="Hello" runAtServer></div>
</div>
Enter fullscreen mode Exit fullscreen mode

Example Components

Hello.js

import 'sigment';

function Hello() {
  return div(
    div({ class: "mycss" }, "what is your name:"),
    input({ type: "text", name: "youname" })
  );
}

export default Hello;
Enter fullscreen mode Exit fullscreen mode

Header.js

import 'sigment';

function Header() {
  return div({ class: "site-header" },
    nav(
      a({ href: "/" }, "Home"),
      " | ",
      a({ href: "/about" }, "About"),
      " | ",
      a({ href: "/hello" }, "Hello"),
      " | ",
      a({ href: "/counter" }, "Counter"),
      " | ",
      a({ href: "/about/1/2" }, "Example with param")
    )
  );
}

export default Header;
Enter fullscreen mode Exit fullscreen mode

Footer.js

import 'sigment';

function Footer() {
  return div("© 2025 Sigment. Built with love for developers");
}

export default Footer;
Enter fullscreen mode Exit fullscreen mode

Components & Features

  • Hello.js: SSR-enabled component. Renders on the server when runAtServer is used.
  • Header.js & Footer.js: Globally loadable SSR components.

Dynamic Props Example: Visiting /about/1/2 automatically injects id=1 and pageid=2 into About.
Multiple Component Instances: Multiple instances (like Hello) can coexist with independent lifecycles and reactive state.

Developer Experience

  • Adding a new page/component is simple: create HTML in src/html and JS in src/components.
  • Layouts are reusable with <layout> and data-part. Components can be SSR or client-only.
  • Dev mode (npm run dev) serves pages as-is without layout transformation for faster iteration.
  • Production mode (npm run build && npm run start) fully processes layouts and SSR components for clean HTML output.

Benefits

  • HTML as source of truth — semantic, clean, and easy to edit.
  • Flexible hybrid rendering — SSR where needed, client-only elsewhere.
  • Lightweight & modular — small bundle sizes, no JSX.
  • SEO & performance friendly — SSR ensures important parts are indexed.
  • Fine-grained control — independent lifecycles per component.

Try It Out

Check the project here: HTML-First Architecture Example

git clone https://github.com/sigmentjs/html-first-architecture-example.git
cd html-first-architecture-example
npm install
npm run build
npm run start
Enter fullscreen mode Exit fullscreen mode

Visit /, /hello, /about/1/2, or /counter to see the architecture in action.

Extending the Architecture

Once you understand the basics, you can extend this architecture for your own projects by:

  • Adding new SSR or client-only components.
  • Creating custom layouts with multiple data-part sections.
  • Using dynamic props from URLs to customize component rendering.
  • Mixing SSR and client-only components to optimize SEO and performance.

Contact Me

You can reach m via email: Yaniv

Top comments (2)

Collapse
 
_ss_04b68c0f666c0cc38 profile image
dan prosfer

Very interesting idea, I'll have to try it out.

Collapse
 
_25439defadc4a1c89754 profile image
יאיר

the html first architecture you show ,looking good
I will try this thanks