ArchitectUI Docs
Live Demo

Adding Pages

A walkthrough of adding new HTML pages to ArchitectUI. Covers template creation, page registration, sidebar nav, per-page scripts, and reusing dashboard chrome.

The Two-Step Process

Every page in ArchitectUI is the combination of two things:

  • A Handlebars template under src/DemoPages/ that defines the page content
  • An entry in src/pages.js that registers the template with HtmlWebpackPlugin so it gets compiled into an HTML file

Adding a page means creating one and registering the other. Webpack scans src/pages.js at startup, so you must restart the dev server after adding new entries — HMR doesn't track new pages.

Create the Template

Create a new .hbs file under src/DemoPages/ in the appropriate category. For example, a new analytics page:

// src/DemoPages/dashboards/my-dashboard.hbs
                
                {{#> base }}
                {{> AppSidebar/sidebar }}
                <div class="app-main__outer">
                    <div class="app-main__inner">
                        {{> AppMain/page-title }}
                
                        <div class="row">
                            <div class="col-md-6">
                                <div class="main-card mb-3 card">
                                    <div class="card-body">
                                        <h5 class="card-title">Hello world</h5>
                                        <p>My dashboard content goes here.</p>
                                    </div>
                                </div>
                            </div>
                        </div>
                
                        {{> AppFooter/footer }}
                    </div>
                </div>
                {{/base}}

Three things to notice:

  • {{#> base }} ... {{/base}} wraps the content in the master layout (header, theme drawer, body classes). The block-partial syntax with #> lets the page contribute content to the master.
  • {{> AppSidebar/sidebar }} includes the dashboard sidebar partial.
  • {{> AppMain/page-title }} renders the page title bar using title, description, and heading_icon values passed from pages.js.

Register the Page

Open src/pages.js and add a new entry to the array. The shape is:

{
                    output: "./my-dashboard.html",                  // relative URL of the output file
                    content: {
                        title: "My Dashboard",                       // page title (in <title> and page header)
                        description: "A custom dashboard example.",  // meta description + page subtitle
                        heading_icon: "pe-7s-car icon-gradient bg-mean-fruit",  // icon class for page header
                    },
                    template: "./src/DemoPages/dashboards/my-dashboard.hbs",
                }

After saving, restart the dev server:

npm start

Visit http://localhost:8080/my-dashboard.html to view the rendered page.

Don't forget to restart. HMR doesn't track new entries in pages.js — the file is read once at webpack startup. Saving pages.js while the dev server runs has no effect.

Page Title Variables

The content object is interpolated into the template via HtmlWebpackPlugin. Within the template, refer to fields as htmlWebpackPlugin.options.[field]:

<title>{{ htmlWebpackPlugin.options.title }} - {{ htmlWebpackPlugin.options.description }}</title>
                <meta name="description" content="{{ htmlWebpackPlugin.options.description }}">

The AppMain/page-title partial reads title, description, and heading_icon automatically.

Page Title Variants

ArchitectUI provides three page-title partials with different layouts:

PartialDescription
AppMain/page-titleDefault — icon, title, description, with optional action buttons on the right
AppMain/page-title-altAlternate layout with breadcrumb support
AppMain/page-title-alt-2Compact variant with smaller icon
AppMain/page-title-actionsJust the action button row (use alongside another title partial)

Swap them by changing the {{> AppMain/... }} partial reference in your page template.

Add the Page to the Sidebar Nav

The dashboard sidebar is hard-coded in src/layout/AppSidebar/sidebar.hbs. To add your page to the nav, edit that file and add a list item. Example — adding "My Dashboard" under the Dashboards group:

<li>
                    <a href="my-dashboard.html">
                        <i class="metismenu-icon pe-7s-car"></i>
                        My Dashboard
                    </a>
                </li>

For a nested sub-menu, use the MetisMenu pattern (a top-level <li> with a child <ul>):

<li>
                    <a href="#">
                        <i class="metismenu-icon pe-7s-rocket"></i>
                        My Section
                        <i class="metismenu-state-icon pe-7s-angle-down caret-left"></i>
                    </a>
                    <ul>
                        <li><a href="my-page-1.html">Page 1</a></li>
                        <li><a href="my-page-2.html">Page 2</a></li>
                    </ul>
                </li>

Sidebar changes propagate to every page that uses {{> AppSidebar/sidebar }} — no other edits needed.

Per-Page JavaScript

Each Webpack entry in webpack.config.js produces a separate JS bundle. Pages only include the bundles they need.

Using an Existing Entry

If your page uses a feature that's already wired up (charts, datatables, form widgets), no JavaScript work is needed — the bundle is already built. Your page will pick it up via the default HtmlWebpackPlugin injection (which injects every entry into every page).

Adding a New Per-Page Feature

For a new feature, create an initializer file and register it as a Webpack entry:

// src/scripts-init/my-feature.js
                import "./my-feature.scss";          // optional SCSS
                
                document.addEventListener("DOMContentLoaded", function () {
                    const els = document.querySelectorAll("[data-my-feature]");
                    if (!els.length) return;
                
                    els.forEach(el => {
                        // initialize the feature on each element
                    });
                });
// webpack.config.js
                entry: {
                    // ...existing entries...
                    my_feature: "./src/scripts-init/my-feature.js",
                }

Restart the dev server and the new entry is bundled. Use it on any page by adding the data-my-feature attribute to a target element.

The initializer pattern always starts with if (!els.length) return; — this guard means the bundle is safe to include on pages that don't use the feature. Webpack injects every entry into every page; the guard keeps the no-op path cheap.

Page Variants

Full-Screen Pages (Auth, Errors)

For pages that should not render the dashboard chrome (sidebar, header, drawer), extend basePages.hbs instead of base.hbs:

{{#> basePages }}
                <div class="h-100 bg-plum-plate bg-animation">
                    <div class="d-flex h-100 justify-content-center align-items-center">
                        {{!-- your full-screen content here --}}
                    </div>
                </div>
                {{/basePages}}

Used by every auth page (login.hbs, register.hbs, etc.).

Documentation Pages

For docs-style pages with their own minimalist shell (top bar + left sidebar + content), extend docsBase.hbs:

{{#> docsBase docsActive="my-page"}}
                <h1 class="docs-page-title">My Page</h1>
                <section>
                    <h2>Section</h2>
                    <p>Content here.</p>
                </section>
                {{/docsBase}}

Add a matching nav entry in src/layout/AppDocs/sidebar.hbs so users can navigate to it.

Conventions and Tips

  • Output paths are relative URLs. "./my-page.html" emits to the root of the dist directory. For nested URLs (e.g. "./admin/users.html") the build creates the subdirectory automatically.
  • Output names should match the URL pattern of nearby pages. Auth pages use pages-*.html, components use components-*.html, docs use docs-*.html. This convention makes file finding easier.
  • Reuse heading_icon classes. The pattern is {icon-class} icon-gradient {bg-gradient-class}. Browse existing dashboards for examples.
  • Wrap page content in {{!-- ...comments... --}} liberally — Handlebars comments are stripped from output and won't show up in HTML.
  • Don't put inline <script> blocks in templates. Create a new entry in src/scripts-init/ instead. Inline scripts are harder to maintain and don't benefit from Webpack's module graph.

Next Steps

See Handlebars Partials for a deeper dive into the partial system, or Components to find pre-built widgets you can compose into new pages.