Skip to main content
This guide will walk you through creating a simple counter app with GlyphUI. By the end, you’ll understand the basics of components, state management, and event handling.

Prerequisites

Make sure you’ve completed the installation steps before continuing.

Create Your First App

1

Create project files

Create a new directory for your app and add two files:
mkdir my-first-app
cd my-first-app
touch index.html app.js
2

Set up the HTML file

Add the following to index.html:
index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My First GlyphUI App</title>
    <style>
      body {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        margin: 0;
        font-family: system-ui, -apple-system, sans-serif;
      }
      button {
        font-size: 1.5rem;
        padding: 10px 20px;
        margin: 0 10px;
        cursor: pointer;
      }
      span {
        font-size: 2rem;
        margin: 0 20px;
      }
    </style>
    <script type="module" src="./app.js"></script>
  </head>
  <body>
    <main id="app"></main>
  </body>
</html>
3

Create the Counter component

Add the following to app.js:
app.js
import {
  Component,
  h,
  hFragment,
  hString,
} from "../packages/runtime/dist/glyphui.js";

class CounterApp extends Component {
  constructor() {
    super({}, {
      initialState: { count: 0 }
    });
  }
  
  increment() {
    this.setState({ count: this.state.count + 1 });
  }
  
  decrement() {
    this.setState({ count: this.state.count - 1 });
  }
  
  render(props, state) {
    return hFragment([
      h("button", { on: { click: () => this.decrement() } }, ["-"]),
      h("span", {}, [
        hString("count is: "),
        hString(state.count),
      ]),
      h("button", { on: { click: () => this.increment() } }, ["+"]),
    ]);
  }
}

// Mount the app
const app = new CounterApp();
app.mount(document.querySelector("#app"));
Adjust the import path based on where your app is located relative to the GlyphUI installation. If your app is in a sibling directory to glyphui/, use ../glyphui/packages/runtime/dist/glyphui.js
4

Run your app

Start a local server from the GlyphUI root directory:
npx http-server . -c-1
Then open your browser to http://localhost:8080/my-first-app/index.html

What You Built

Congratulations! You’ve created a working counter app. Let’s break down what each part does:

Component Class

class CounterApp extends Component {
  constructor() {
    super({}, {
      initialState: { count: 0 }
    });
  }
  • Extends Component: All GlyphUI components extend the Component base class
  • Initial State: The initialState object defines the component’s starting state
  • State is accessible via this.state throughout the component

Event Handlers

increment() {
  this.setState({ count: this.state.count + 1 });
}
  • Methods define behavior for user interactions
  • this.setState() updates state and triggers a re-render
  • The component automatically updates the UI when state changes

Render Method

render(props, state) {
  return hFragment([
    h("button", { on: { click: () => this.decrement() } }, ["-"]),
    h("span", {}, [hString("count is: "), hString(state.count)]),
    h("button", { on: { click: () => this.increment() } }, ["+"]),
  ]);
}
  • h() function: Creates virtual DOM elements (like React.createElement)
  • hFragment(): Groups multiple elements without a wrapper
  • hString(): Creates text nodes
  • Event binding: on: { click: handler } attaches event listeners

Mounting

const app = new CounterApp();
app.mount(document.querySelector("#app"));
  • Creates an instance of your component
  • Mounts it to a DOM element to render the UI

Try a Different Example

Here’s a “Hello World” app with changing greetings:
import { h, Component } from "../packages/runtime/dist/glyphui.js";

class HelloWorldApp extends Component {
  constructor() {
    super({}, {
      initialState: { greeting: "Hello, World!" },
    });

    this.greetings = [
      "Hello, World!",
      "Hola, Mundo!",
      "Bonjour, Monde!",
      "Ciao, Mondo!",
      "こんにちは世界!",
      "你好,世界!",
      "Привет, мир!",
    ];
  }

  changeGreeting() {
    const currentIndex = this.greetings.indexOf(this.state.greeting);
    const nextIndex = (currentIndex + 1) % this.greetings.length;
    this.setState({ greeting: this.greetings[nextIndex] });
  }

  render(props, state) {
    return h("div", {}, [
      h("div", { class: "greeting" }, [state.greeting]),
      h(
        "button",
        {
          class: "change-btn",
          on: { click: () => this.changeGreeting() },
        },
        ["Next →"]
      ),
    ]);
  }
}

// Mount the app
const app = new HelloWorldApp();
app.mount(document.querySelector("#app"));
This example demonstrates:
  • Storing arrays in the component instance
  • Cycling through values
  • Applying CSS classes to elements

Explore More Examples

The GlyphUI repository includes several complete examples:

Counter

Simple counter with increment/decrementexamples/counter/counter.html

Todo App

Full todo app with state managementexamples/vercel-todo/index.html

Tic-Tac-Toe

Game with complex state logicexamples/tictactoe/index.html

Lazy Loading

Code splitting with Suspenseexamples/lazy-loading/index.html
Run npm run serve:examples from the project root to explore all examples in your browser.

Next Steps

Now that you’ve built your first app, dive deeper into GlyphUI’s features:

Virtual DOM

Learn how the h() function creates virtual elements

Components

Master component lifecycle and composition

State Management

Use stores for global state

Hooks

Use hooks for state and effects

Build docs developers (and LLMs) love