Skip to content

Repository files navigation

HOT Shared UI

HOT

Shared Web Components with theming for use across HOTOSM tools.

Publish Tests CDN Deploy Publish Docs Package version Downloads License

📖 Documentation: https://ui.hotosm.org

🖥️ Source Code: https://github.com/hotosm/ui

🎯 Roadmap / Tasks: https://github.com/orgs/hotosm/projects/37/views/3


Overview

Shared Web Components built with Lit and themed for HOTOSM tools using WebAwesome primitives.

Goals:

  • Reduce code duplication across HOT tools.
  • Provide a consistent HOT look-and-feel out of the box.
  • Keep the component set small and focused (header, sidebar, footer, etc.).

WebAwesome version: 3.11.0


Installation

pnpm install @hotosm/ui @awesome.me/webawesome@3.11.0

Note

@awesome.me/webawesome is a peer dependency. Always pin it to the version shown above to avoid conflicts between HOT components and WebAwesome internals.


Loading Styles

Use the single self-contained stylesheet (WebAwesome base styles + HOT theme inlined):

import "@hotosm/ui/dist/style.css";

Or from CDN:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@hotosm/ui@1.0.0/dist/style.css" />

style-core.css (HOT theme only, no WebAwesome) exists for pages that load the WebAwesome base stylesheets themselves - most apps don't need it.

Fonts

There are none to load. Since 2026-08-27 the design system uses the platform's own sans stack - no Archivo, no Barlow, no webfonts at all.

See MADR 0014 for the rationale.


HTML Setup

Add the required WebAwesome classes to your <html> element:

<!DOCTYPE html>
<html class="wa-theme-default wa-palette-hotosm">
  <head>
    ...
  </head>
  <body>
    ...
  </body>
</html>

Important

These classes activate the HOT colour palette and light theme for every WebAwesome component on the page. Do not remove them.


Using Components

Via Bundler (Vite, Webpack, etc.)

Recommended: register all WebAwesome elements once, up front, so every custom element is defined before first render - this eliminates flash of undefined custom elements (FOUCE) without maintaining per-page import lists:

import "@hotosm/ui/dist/style.css";
import "@hotosm/ui/dist/webawesome-all.js"; // registers every wa-* element
import "@hotosm/ui/dist/components/header/header.js"; // hot-* components you use
<hot-header title="My App"></hot-header>

Build setup

@hotosm/ui/vite provides build helpers for Vite 5, 7, and 8.

Add the circular chunk guard to catch chunk cycles that can cause a blank page at runtime:

// vite.config.ts
import { circularChunkGuard } from "@hotosm/ui/vite";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [circularChunkGuard()],
});

Keep the guard enabled even if you do not split chunks manually. Dependency updates can also introduce cycles.

You can also place WebAwesome in its own chunk. This lets browsers keep it cached when the rest of your app changes:

For Vite 8:

// vite.config.ts
import { WEBAWESOME_CHUNK } from "@hotosm/ui/vite";
import { defineConfig } from "vite";

export default defineConfig({
  build: {
    rolldownOptions: {
      output: {
        codeSplitting: {
          groups: [WEBAWESOME_CHUNK],
        },
      },
    },
  },
});

For Vite 5-7:

// vite.config.ts
import { matchWebawesome } from "@hotosm/ui/vite";
import { defineConfig } from "vite";

export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: (id) => matchWebawesome(id),
      },
    },
  },
});

This cache is per origin, so it is reused across deployments of the same app, not across different HOT tools.

Via CDN / Plain HTML / HTMX

Load the raw dist files, with an import map to resolve the bare @awesome.me/webawesome/... imports in webawesome-all.js. The map's WebAwesome pin must match the version this @hotosm/ui release was built against. Do not use jsDelivr's /+esm URLs - they duplicate element registrations and most wa-* elements never register.

<!DOCTYPE html>
<!-- wa-cloak: hides the page until all custom elements are defined (2s max) -->
<html class="wa-theme-default wa-palette-hotosm wa-cloak">
  <head>
    <!-- Fonts: see "Fonts" above -->

    <!-- WebAwesome base styles + HOT theme, self-contained -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@hotosm/ui@1.0.0/dist/style.css" />

    <script type="importmap">
      {
        "imports": {
          "@awesome.me/webawesome/dist/components/": "https://cdn.jsdelivr.net/npm/@awesome.me/webawesome@3.11.0/dist-cdn/components/"
        }
      }
    </script>

    <!-- Register every wa-* element, then the hot-* components -->
    <script
      type="module"
      src="https://cdn.jsdelivr.net/npm/@hotosm/ui@1.0.0/dist/webawesome-all.js"
    ></script>
    <script
      type="module"
      src="https://cdn.jsdelivr.net/npm/@hotosm/ui@1.0.0/dist/hotosm-ui.js"
    ></script>
  </head>

  <body>
    <hot-header id="hdr" title="My App" size="s" show-login></hot-header>

    <script>
      // Boolean props default to false.
      // Include the attribute to make it true.
      const hdr = document.getElementById("hdr");
      hdr.drawer = true; // enable the hamburger drawer
    </script>
  </body>
</html>

For multi-page (HTMX) apps, also inline a few critical theme tokens in <head> so first paint looks right before the CDN CSS arrives - see Loading Strategies.

React

Web Components work in React with a small caveat - use ref callbacks for custom events if React's synthetic event system doesn't forward them:

import "@hotosm/ui/dist/components/header/header.js";

function App() {
  return (
    <hot-header
      title="My App"
      ref={(el) => {
        if (el) el.addEventListener("login", () => console.log("logged in"));
      }}
    />
  );
}

Using HOT Design Tokens

The HOT theme exposes CSS custom properties you can reference in your own stylesheets:

.my-card {
  background: var(--hot-color-primary-50);
  color: var(--hot-color-neutral-900);
  font-family: var(--hot-font-sans);
  padding: var(--hot-spacing-medium);
  border-radius: var(--hot-border-radius-large);
}

See all available tokens in src/themes/hot.css.


Component Guides

  • Header: see header.md for detailed integration, styling, and framework examples.

Contributing

git clone git@github.com:hotosm/ui.git
cd ui
pnpm install
pnpm run dev        # starts Storybook on localhost:3001

Styling files (under src/themes/):

File Purpose
hot.css HOT design tokens (colours, typography, spacing)
hot-wa.css WebAwesome variable overrides to apply the HOT palette

License

HOT UI is free and open source software. You may use any HOT UI project under the terms of the GNU General Public License (GPL) Version 3.

About

Shared UI components with HOT theming

Resources

Stars

9 stars

Watchers

7 watching

Forks

Releases

Packages

Used by

Contributors

Languages