Skip to content
xiriframeworkPublic

About

JSON-driven Angular UI component library for building modern data-driven applications.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

xiri-ng

JSON-driven Angular UI component library for building modern data-driven applications.

Overview

xiri-ng is a configuration-driven Angular component library where the backend controls the UI via JSON structures. Instead of writing Angular templates for every page, you define your UI as JSON on the server, and xiri-ng renders it automatically. This enables a clean separation: the backend decides what to show, and xiri-ng decides how to show it.

Perfect companion to xiri-go: The Go backend framework that generates type-safe JSON structures for xiri-ng. Together, they form the Xiri Framework - a complete stack for building enterprise applications with Go backends and Angular frontends.

Features

  • 40+ standalone Angular components ready for production use
  • Configuration-driven forms with 20+ field types, validation, and server-side search
  • Feature-rich tables with sorting, filtering, pagination, inline editing, and footer aggregations
  • Modern UI components: Page headers, sections, toolbars, breadcrumbs, timelines, stats, description lists, skeletons, empty states
  • Dynamic page rendering: URL → API call → fully rendered UI
  • Responsive grid system (xcol-md-{1-12})
  • Material Design 3 theming with light/dark/auto mode
  • Built on Angular 21 and Angular Material 21 with standalone components
  • Tree-shakeable: Only import what you use
  • Extensible via xiri-dyncomponent template overrides
  • Type-safe when paired with xiri-go

Installation

npm install @xiriframework/xiri-ng

Peer Dependencies

Angular 22, Angular Material 22, date-fns 4, RxJS 7, material-symbols. See package.json for the full list. Icon setup: see the library README.

Quick Start

Configure the library in your application bootstrap:

import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient } from '@angular/common/http';
import { provideXiriServices } from '@xiriframework/xiri-ng';
import { AppComponent } from './app.component';

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(),
    provideXiriServices({ api: '/api/' }),
  ]
});

Use xiri-dyncomponent to render JSON-driven UI:

import { Component } from '@angular/core';
import { XiriDynComponentComponent, XiriDynData } from '@xiriframework/xiri-ng';

@Component({
  selector: 'app-dashboard',
  standalone: true,
  imports: [XiriDynComponentComponent],
  template: `<xiri-dyncomponent [data]="components" />`
})
export class DashboardComponent {
  components: XiriDynData[] = [
    {
      type: 'card',
      display: 'xcol-md-6',
      data: {
        header: 'Users',
        headerIcon: 'people',
        data: { count: 42 },
        fields: [{ id: 'count', name: 'Total', format: 'number' }]
      }
    },
    {
      type: 'table',
      data: {
        url: '/api/users',
        fields: [
          { id: 'name', name: 'Name', format: 'text', sort: true },
          { id: 'email', name: 'Email', format: 'text', sort: true }
        ]
      }
    }
  ];
}

Start a new project (full stack)

A Xiri app is two halves: a xiri-go backend that emits JSON, and this xiri-ng frontend that renders it. The whole frontend is usually a single "DynPage" route — every URL fetches the matching API endpoint and renders the response. Three wiring steps:

1. Providers (main.ts) — services + a wildcard route to one DynPage component:

import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient } from '@angular/common/http';
import { provideRouter, withRouterConfig } from '@angular/router';
import { provideXiriServices } from '@xiriframework/xiri-ng';
import { AppComponent } from './app/app.component';
import { DynpageComponent } from './app/dynpage.component'; // see "Dynamic Pages" below

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(),
    provideXiriServices({ api: '/api/' }),
    // onSameUrlNavigation:'reload' makes refresh:"page" / navigation reload the DynPage
    provideRouter([ { path: '**', component: DynpageComponent } ],
      withRouterConfig({ onSameUrlNavigation: 'reload' })),
  ]
});

2. Proxy (proxy.conf.json, referenced from angular.json serve.options.proxyConfig) — forward /api to your xiri-go server:

{ "/api": { "target": "http://localhost:8080", "secure": false } }

3. DynPage component — copy the one from Dynamic Pages below. That's the entire frontend; new screens are added purely on the backend.

Let Claude build it — install both skills

The fastest way to start (without reading every API) is to install both bundled Claude Code skills, then describe the screen you want:

  • xiri-ng-expert — bundled in this repo (install). The Angular side: providers, xiri-dyncomponent, tables, forms, theming.
  • xiri-go-expert — bundled in xiri-go. The Go side: component/table/form/dialog builders, responses, routing.

With both active, Claude scaffolds the backend handlers and the matching frontend from one prompt.

Component Overview

Data Entry

Component Type Description
Form form Dynamic form with field generation from JSON configuration
Text, Email, Number, Password, Textarea Field types Standard input fields with validation
Select / Multi-Select select, multiselect Dropdowns with built-in search (ngx-mat-select-search)
Tree Select treeselect Hierarchical tree selection
Date / DateTime date, datetime Date and datetime pickers (date-fns)
Date Range / DateTime Range daterange, datetimerange Range pickers for start/end dates
File Upload file File upload with drag-and-drop, accepts filters
Volume volume Specialized volume/capacity input
Time Limit timelimit Duration input (days/hours/minutes)

Data Display

Component Type Description
Table table Data table with server-side sorting, filtering, pagination, inline editing, footer aggregations
Raw Table - Simple table for basic data display
Card card Structured data display with header, icon, and action buttons
Card Link cardlink Clickable navigation card
List list List display
Stat stat Single statistic/KPI display with value, label, icon, trend, and color theming
Stat Grid stat-grid Grid layout for multiple statistics
Description List description-list Key-value pairs display (like a definition list)
Timeline timeline Vertical timeline for events/activities
Info Point infopoint Information tooltip
Image Text imagetext Image with text content
Links links Link list display

Layout and Navigation

Component Type Description
Page Header page-header Modern page header with title, subtitle, icon, and color theming
Section section Content section with optional title, subtitle, icon, and divider
Toolbar toolbar Action toolbar with title and buttons
Header header Simple text header with color + size (e.g. for inline section titles)
Breadcrumb breadcrumb Breadcrumb navigation trail
Sidenav - Side navigation
Tabs tabs Tabbed content
Expansion expansion Expandable panels
Container container Nested component grouping
Spacer spacer Layout spacing
Divider divider Visual content divider with optional text
Button Line buttonline Row of action buttons
Button - Styled button (raised, flat, stroked, icon, fab)
Search - Search component

Feedback and Status

Component Type Description
Alert - Alert messages
Dialog - Modal dialogs
Done - Success/completion display
Error - Error display
Multi Progress multiprogress Multiple progress indicators
Skeleton - Loading skeleton placeholders
Empty State - Empty state display
Snackbar Service - Toast notifications (success, error, info, warning)

Dynamic Rendering

Component Type Description
DynComponent - Renders XiriDynData[] arrays into UI
Stepper stepper Multi-step workflows
Query query Search/filter interface with dynamic result rendering

Utilities

Export Description
SafehtmlPipe Pipe for rendering trusted HTML
ColorType Theme color type definitions

Services

Service Description
XiriDataService Central HTTP service. Prepends the configured api base URL to all requests. Methods: get(), post(), postFile(), postFileResponse()
XiriDateService Date manipulation utilities wrapping date-fns with timezone support
XiriNumberService Number formatting and validation
ThemeService Material Design 3 theme management. Supports light, dark, and auto modes. Persists preference to localStorage
XiriFormService Form state management across components
XiriLocalStorageService Type-safe localStorage wrapper
XiriSessionStorageService Type-safe sessionStorage wrapper
XiriSnackbarService Snackbar notifications with typed methods: success(), error(), info(), warning()

Dynamic Pages (DynPage)

The core pattern for xiri-ng applications: the current URL maps to an API call, and the response is rendered as a full page.

URL: /users         GET /api/users
                          |
                          v
                    { bread: [...], data: XiriDynData[] }
                          |
                          v
                    xiri-dyncomponent renders the page

Implementation — this is the complete DynPage component (same as the demo app). It is registered once on the ** wildcard route (see Start a new project), and every URL in your app routes through it. There is no library-exported page component on purpose — copy this ~40-line component into your app and you never touch it again; new screens are added purely on the backend.

import { Component, inject, OnDestroy, OnInit, signal } from '@angular/core';
import { ActivatedRoute, Event, NavigationEnd, Router } from '@angular/router';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { filter } from 'rxjs/operators';
import { Observable, Subscription } from 'rxjs';
import { MatProgressSpinner } from '@angular/material/progress-spinner';
import { XiriDataService, XiriDynComponentComponent, XiriDynData } from '@xiriframework/xiri-ng';

@Component({
  selector: 'app-dynpage',
  imports: [MatProgressSpinner, XiriDynComponentComponent],
  template: `
    @if (loading) { <mat-spinner diameter="30" /> }
    @if (error) { <h1>Page not found</h1> }
    <xiri-dyncomponent [data]="data()" />
  `,
})
export class DynpageComponent implements OnInit, OnDestroy {
  private dataService = inject(XiriDataService);
  private router = inject(Router);
  private route = inject(ActivatedRoute);

  loading = true;
  error = false;
  bread: any = null;
  data = signal<XiriDynData[] | null>(null);
  private subs = new Subscription();

  constructor() {
    // Re-load on every navigation (works with onSameUrlNavigation:'reload')
    this.router.events.pipe(
      filter((e: Event) => e instanceof NavigationEnd),
      takeUntilDestroyed(),
    ).subscribe(() => this.load());
  }

  ngOnInit() { this.load(); }

  private load() {
    this.loading = true;
    this.data.set(null);
    this.bread = null;
    this.error = false;

    let url = this.router.url;
    if (url.startsWith('/')) url = url.substring(1); // strip leading /

    // No query params → GET; with query params → POST them as the body
    const qp = this.route.snapshot.queryParams;
    const call: Observable<any> = Object.keys(qp).length === 0
      ? this.dataService.get(url)
      : this.dataService.post(url, qp);

    this.subs.add(call.subscribe({
      next: (res: any) => { this.bread = res.bread; this.data.set(res.data); this.loading = false; },
      error: () => { this.error = true; this.loading = false; },
    }));
  }

  ngOnDestroy() { this.subs.unsubscribe(); }
}

The backend returns { bread?: ..., data: XiriDynData[] } and xiri-dyncomponent renders cards, tables, forms, and any other component types automatically. (The demo app's copy lives at projects/demo/src/app/dynpage/.)

Using with xiri-go

xiri-go is the official Go backend framework for xiri-ng. It provides type-safe builders for all xiri-ng components, eliminating manual JSON writing and preventing configuration errors.

Why xiri-go?

  • ✅ Type-safe component generation - No more JSON typos or missing fields
  • ✅ Fluent API - Chainable builder methods for readable code
  • ✅ Full component coverage - All xiri-ng components have Go equivalents
  • ✅ Integrated with Echo framework - Built-in routing and middleware
  • ✅ Auto-complete support - Your IDE knows all component options

Example: Building a Dashboard

package main

import (
    "time"

    "github.com/labstack/echo/v4"
    "github.com/xiriframework/xiri-go/component/core"
    "github.com/xiriframework/xiri-go/component/page"
    "github.com/xiriframework/xiri-go/component/pageheader"
    "github.com/xiriframework/xiri-go/component/stat"
    "github.com/xiriframework/xiri-go/component/statgrid"
    "github.com/xiriframework/xiri-go/component/table"
    xurl "github.com/xiriframework/xiri-go/component/url"
)

type User struct {
    ID        int64
    Name      string
    Email     string
    LastLogin time.Time
}

func dashboardPage(c echo.Context) error {
    // Page header with title, subtitle, icon
    header := pageheader.New("User Dashboard").
        Subtitle("Overview of all users").
        Icon("dashboard", core.ColorPrimary)

    // Statistics grid — stat.New(value, label)
    stats := statgrid.New().Columns(2)
    stats.Add(stat.New("1,234", "Total Users").
        Icon("people").
        SetTrend(12.0, stat.TrendUp))
    stats.Add(stat.New("892", "Active Today").
        Icon("trending_up").
        IconColor("accent"))   // stat.IconColor takes a string (not core.Color)

    // Data table — generic builder over Row type
    b := table.NewBuilder[User]()
    b.IdField  ("id",        "ID",         func(r User) int64     { return r.ID })
    b.TextField("name",      "Name",       func(r User) string    { return r.Name }).WithSort(true)
    b.TextField("email",     "Email",      func(r User) string    { return r.Email }).WithSort(true)
    b.DateTimeField("login", "Last Login", func(r User) time.Time { return r.LastLogin }).WithSort(true)
    tbl := b.Build()
    tbl.SetURL(xurl.NewUrlPrefix("/users/data", "/api"))

    // Assemble page and return
    p := page.NewPage()
    p.Add(header)
    p.Add(stats)
    p.Add(tbl)
    return c.JSON(200, p.Print(nil))
}

This Go code produces the JSON that xiri-ng's xiri-dyncomponent automatically renders into a complete dashboard page with header, statistics, and data table. See the xiri-go-expert Claude skill bundled in that repo for a full API reference.

Getting Started with xiri-go

go get github.com/xiriframework/xiri-go

See the xiri-go repository for full documentation, examples, and API reference.

Grid System

Use the display property on XiriDynData to control responsive layout:

Class Breakpoint
xcol Full width (default)
xcol-sm-{1-12} Small screens
xcol-md-{1-12} Medium screens (>= 768px)
xcol-lg-{1-12} Large screens (>= 1024px)
xcol-xl-{1-12} Extra large screens (>= 1280px)

Combine classes for responsive behavior:

{ "display": "xcol-md-6 xcol-lg-4" }

This renders full width on mobile, half width on medium screens, and one-third on large screens.

Theming

xiri-ng uses the Angular Material Design 3 theming system with SCSS.

The ThemeService manages theme state:

import { ThemeService } from '@xiriframework/xiri-ng';

export class MyComponent {
  private theme = inject(ThemeService);

  toggleTheme() {
    this.theme.toggle(); // Switches between light and dark
  }

  setAuto() {
    this.theme.resetToAuto(); // Follow system preference
  }
}

Modes: light, dark, auto (follows prefers-color-scheme). The preference is persisted in localStorage.

Development

Setup

# Install dependencies
npm install

# Start dev server (localhost:4301, proxies /api to localhost:8080)
npm start

# Build the library
npm run build

# Run tests
npm test

# Run linting
npm run lint

Publishing (for maintainers)

# Automated release workflow (recommended)
npm run publish
# This will:
# 1. Bump patch version (0.2.0 → 0.2.1)
# 2. Build the library
# 3. Create git commit and tag (v0.2.1)
# 4. Push to GitHub
# 5. GitHub Actions automatically publishes to npm

# Manual version bumps
cd projects/xiri-ng
npm version minor  # or major
cd ../..
git add projects/xiri-ng/package.json
git commit -m "Bump to version X.Y.Z"
git tag vX.Y.Z
git push --follow-tags

Demo Application

The projects/demo/ directory contains a demo application that showcases library components:

npm start
# Open http://localhost:4301/web/

The demo proxies /api requests to http://localhost:8080, so you can run a backend (e.g., a xiri-go application) alongside it.

API Reference

For a deep API reference (every component's inputs/outputs, services, pipes, types) use the bundled Claude Code skill — see Claude Code Integration below. The skill has 7 reference files covering setup, dyncomponent, form fields, tables, components, and theming.

Requirements

Dependency Version
Angular ^22.0
Angular Material ^22.0
Angular CDK ^22.0
date-fns ^4.3
@date-fns/tz ^1.5
RxJS ^7.8.2
ngx-mat-select-search ^9.0.0
material-symbols >= 0.44
echarts (optional) ^6.1

Claude Code Integration — xiri-ng-expert Skill

Dieses Repo enthält einen bundled Claude Code Skill unter skills/xiri-ng-expert/, der Claude beim Schreiben von Angular-Code mit xiri-ng unterstützt. Der Skill wird mit jedem Library-Release mit-versioniert, sodass die Skill-Inhalte (Komponenten-APIs, Interfaces, Patterns) zur installierten Library-Version passen.

Was der Skill kann

Sobald aktiviert, triggert der Skill automatisch, wenn du Angular-Code schreibst oder Fragen stellst zu:

  • Setup: provideXiriServices, XiriDataService, XiriSnackbarService, XiriResponseHandlerService, Theme + Storage Services
  • xiri-dyncomponent: Rendering von XiriDynData[], alle 27 type-Werte, Custom-Rendering via TemplateRef
  • Formulare: XiriFormFieldsComponent, alle 19 Feldtypen, showWhen-Conditional-Visibility, select-Directive
  • Tabellen: XiriTableComponent und XiriRawTableComponent — Settings, Fields, Server-Side-Pagination, Inline-Edit
  • Komponenten: Card, Dialog, Stepper, Tabs, Expansion, Timeline, Stat/StatGrid, Page-Header, Toolbar, …
  • Farben/Types: XiriColor (Theme + Extended), XiriButton, XiriButtonResult, etc.
  • Theming & i18n: Material Design 3, ThemeService-Signals, Locale-Propagation

Installation — Variante A: via skills-lock.json

Wenn dein Projekt den standardisierten skills-lock.json-Mechanismus nutzt, trage einen Eintrag ein, der auf einen Release-Tag verweist:

{
  "version": 1,
  "skills": {
    "xiri-ng-expert": {
      "source": "xiriframework/xiri-ng",
      "sourceType": "github",
      "ref": "v0.2.18"
    }
  }
}

Ersetze v0.2.18 durch den Tag, der zu deiner installierten @xiriframework/xiri-ng-Version passt (npm list @xiriframework/xiri-ng).

Installation — Variante B: Direkt aus node_modules

Weil der Skill nicht im npm-Package liegt (er lebt im Git-Repo), clone oder sparse-checkout das Repo und verlinke den Skill-Ordner:

# Sparse clone (nur skills/ holen)
git clone --depth 1 --branch v0.2.18 --filter=blob:none --sparse \
  https://github.com/xiriframework/xiri-ng.git /tmp/xiri-ng-skill
cd /tmp/xiri-ng-skill && git sparse-checkout set skills
cd -

# Als Symlink in dein Projekt
mkdir -p .claude/skills
ln -s /tmp/xiri-ng-skill/skills/xiri-ng-expert .claude/skills/xiri-ng-expert

# ODER Kopieren (statisch):
cp -r /tmp/xiri-ng-skill/skills/xiri-ng-expert .claude/skills/

Installation — Variante C: Global als User-Skill

Wenn du xiri-ng in mehreren Projekten nutzt:

git clone --depth 1 --branch v0.2.18 https://github.com/xiriframework/xiri-ng.git /tmp/xiri-ng
cp -r /tmp/xiri-ng/skills/xiri-ng-expert ~/.claude/skills/
rm -rf /tmp/xiri-ng

Aktualisieren nach einem npm update: den globalen Skill-Ordner mit dem passenden Tag neu ziehen.

Skill-Struktur

skills/xiri-ng-expert/
├── SKILL.md                    # Navigation + Quick-Refs (always-loaded sobald Skill triggert)
├── references/                  # On-demand (nur wenn Claude liest)
│   ├── setup.md                 # provideXiriServices + alle Services im Detail
│   ├── dyncomponent.md          # xiri-dyncomponent + alle XiriDynData-Typen
│   ├── form-fields.md           # XiriFormFieldsComponent + 19 Feldtypen + showWhen
│   ├── table.md                 # XiriTable + XiriRawTable + Server-Side-Flow
│   ├── components.md            # Kompakt-Signaturen aller weiteren Komponenten
│   └── theming-i18n.md          # XiriColor, ThemeService, Locale-Setup
└── evals/
    └── evals.json               # Test-Prompts für skill-creator

Kompatibilität

Der Skill ist an den Source-Code dieses Tags gekoppelt. Skill und Library-Version sollten immer synchron sein.

License

Apache-2.0

About

JSON-driven Angular UI component library for building modern data-driven applications.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages