npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@semos-labs/glyph

v0.2.10

Published

A React renderer for terminal UIs with flexbox layout

Downloads

414

Readme


Glyph is a React renderer for the terminal. It handles layout, focus, keyboard input, and ships a full component library — write TUI apps the same way you write web apps.


Why Glyph

Built for full-screen, keyboard-driven applications — dashboards, editors, form wizards, dev tools. Not for simple CLI output or argument parsing.

Everything is declarative: you describe layout and focus order, Glyph handles rendering and navigation.

  • Flexbox layout — Yoga handles rows, columns, wrapping, alignment, gaps, padding. No coordinate math.
  • Focus system — Tab navigation, focus scopes, modal trapping, JumpNav (vim-style quick-jump hints).
  • 20+ components — Input, Button, Select, Checkbox, Radio, ScrollView, List, Menu, Progress, Spinner, Image, Toasts, Dialogs, Portal, and more.
  • Character-level diffing — Double-buffered framebuffer. Only changed cells hit stdout.
  • TypeScript-first — Every prop, style, and hook is typed.

How it compares: Ink uses React + Yoga but ships ~4 components with limited focus. Blessed has widgets but is imperative, unmaintained, and JS-only. Textual (Python) and Bubbletea (Go) serve their ecosystems well; Glyph is the equivalent for TypeScript/React. Full comparison →


Quick Start

Scaffold a new project:

bun create @semos-labs/glyph my-app   # or: npm / pnpm / yarn create
cd my-app && bun install && bun dev

Or add to an existing project:

bun add @semos-labs/glyph react
# or: npm install / pnpm add

Hello World

Create app.tsx:

import React from "react";
import { render, Box, Text, Keybind, useApp } from "@semos-labs/glyph";

function App() {
  const { exit } = useApp();

  return (
    <Box style={{ border: "round", borderColor: "cyan", padding: 1 }}>
      <Text style={{ bold: true, color: "green" }}>Hello, Glyph!</Text>
      <Keybind keypress="q" onPress={() => exit()} />
    </Box>
  );
}

render(<App />);
npx tsx app.tsx

A rounded cyan box with bold green text appears. Press q to exit.


Getting Started

A form with flexbox layout, text input, a dropdown, and keyboard navigation:

import React, { useState } from "react";
import { render, Box, Text, Input, Select, Button, Keybind, useApp } from "@semos-labs/glyph";

function App() {
  const { exit } = useApp();
  const [name, setName] = useState("");
  const [lang, setLang] = useState<string | undefined>();

  return (
    <Box style={{ flexDirection: "column", gap: 1, padding: 1, border: "round", borderColor: "cyan" }}>
      <Text style={{ bold: true }}>New Project</Text>

      <Input value={name} onChange={setName} placeholder="Project name..." />

      <Select
        items={[
          { label: "TypeScript", value: "ts" },
          { label: "JavaScript", value: "js" },
          { label: "Go", value: "go" },
        ]}
        value={lang}
        onChange={setLang}
        placeholder="Language"
      />

      <Box style={{ flexDirection: "row", gap: 2 }}>
        <Button onPress={() => { /* create project */ }}>
          <Text>Create</Text>
        </Button>
        <Button onPress={() => exit()}>
          <Text style={{ dim: true }}>Cancel</Text>
        </Button>
      </Box>

      <Keybind keypress="escape" onPress={() => exit()} />
    </Box>
  );
}

render(<App />);

Tab between fields, type to filter the select, Enter to submit. Focus order is automatic.

Components and Hooks

What Glyph ships:

Layout & Text<Box>, <Text>, <Spacer> Form Controls<Input>, <Button>, <Checkbox>, <Radio>, <Select> Lists & Menus<List>, <Menu>, <ScrollView> (with virtualization) Overlays<Portal>, <FocusScope>, <ToastHost>, <DialogHost> Utilities<Keybind>, <JumpNav>, <Progress>, <Spinner>, <Image> HooksuseInput, useFocus, useFocusable, useLayout, useApp, useToast, useDialog

Styling uses a style prop with CSS-like flexbox properties: flexDirection, gap, padding, border, bg, color, bold, and more. Colors accept named values, hex, RGB, and 256-palette with auto-contrast on colored backgrounds.

Full API reference and guides: semos.sh/docs/glyph


Examples

| Example | Description | Source | |---------|-------------|--------| | dashboard | Full task manager using all components | View → | | modal-input | Modal dialogs with focus trapping | View → | | jump-nav | Vim-style keyboard hints for navigation | View → | | forms-demo | Checkbox, Radio, and form controls | View → | | virtualized-list | ScrollView with 10k+ items | View → | | showcase | Progress bars, Spinners, Toasts | View → |

See all examples →

# Run locally
git clone https://github.com/semos-labs/glyph.git && cd glyph
bun install && bun run build
bun run --filter dashboard dev

Built with Glyph

Using Glyph in your project? Let us know!


Comparison

Side-by-side with other TUI frameworks:

| | Glyph | Ink | Blessed | Textual | Bubbletea | |---|:---:|:---:|:---:|:---:|:---:| | Language | TypeScript | TypeScript | JavaScript | Python | Go | | Paradigm | React (JSX) | React (JSX) | Imperative | Declarative (Python) | Elm architecture | | Layout | Yoga flexbox | Yoga flexbox | Custom grid | CSS subset | Manual (lipgloss) | | Built-in components | 20+ | ~4 (Box, Text, Spacer, Newline) | 30+ (widgets) | 30+ (widgets) | BYO (bubbles library) | | Input, Select, Checkbox, … | ✅ Built-in | ❌ Community packages | ✅ Built-in | ✅ Built-in | ❌ Separate library | | Focus system | ✅ Tab, scopes, trapping | ⚠️ Basic | ⚠️ Basic | ✅ Full | ❌ Manual | | JumpNav (vim-hints) | ✅ | ❌ | ❌ | ❌ | ❌ | | Rendering | Character-level diffing | Full re-render | Full re-render | Dirty widget re-render | Full re-render | | Framebuffer | ✅ Double-buffered | ❌ | ❌ | ❌ | ❌ | | True color (hex, RGB) | ✅ + auto-contrast | Via chalk | Partial | ✅ | Via lipgloss | | Image support | ✅ Kitty/iTerm2 | ❌ | ❌ | ❌ | ❌ | | Toasts & Dialogs | ✅ Built-in | ❌ | ❌ | ✅ | ❌ | | Borders | 4 styles | ❌ (ink-box) | ✅ | ✅ | Via lipgloss | | Maintained | ✅ Active | ⚠️ Slow | ❌ Abandoned | ✅ Active | ✅ Active |


Architecture

Render pipeline: React reconciler → GlyphNode tree → Yoga flexbox layout → framebuffer rasterization → character-level diff → stdout.

Source: reconciler/, layout/, paint/, runtime/, components/, hooks/, render.ts. See docs for internals.


License

MIT