Skip to content

iyulab/u-widgets

Repository files navigation

u-widgets

npm npm MCP license jsdelivr

Declarative, data-driven widget system for visualization and input.

Define your data. Map it to visual channels. The renderer does the rest.

{
  "widget": "chart.bar",
  "data": [
    { "name": "A", "value": 30 },
    { "name": "B", "value": 70 },
    { "name": "C", "value": 45 }
  ]
}

That's a complete bar chart. Mapping is auto-inferred from data shape.

Installation

npm install @iyulab/u-widgets
<script type="module">
  import '@iyulab/u-widgets';
  // For chart support (requires echarts peer dependency):
  // import '@iyulab/u-widgets/charts';
  // For math expression support (requires katex peer dependency):
  // import '@iyulab/u-widgets/math';
</script>

<u-widget .spec=${{ widget: 'metric', data: { value: 42, unit: 'users' } }}></u-widget>

CDN

<script src="https://cdn.jsdelivr.net/npm/@iyulab/u-widgets/dist/u-widgets.global.js"></script>

Widget Types

Widget Purpose
chart.bar, chart.line, chart.area, chart.pie, chart.scatter, chart.radar Data visualization
metric, stat-group KPI numbers
gauge, progress Value within range
table, list, kv Structured data
code, citation, status, steps, rating, video, gallery Content display
math LaTeX math expressions (requires katex)
form, confirm User input
compose Widget composition

Quick Examples

// Metric
{ "widget": "metric", "data": { "value": 1284, "unit": "EA", "change": 12.5, "trend": "up" } }

// Table (columns auto-inferred)
{ "widget": "table", "data": [{ "name": "Alice", "role": "Engineer" }, { "name": "Bob", "role": "Designer" }] }

// Form
{ "widget": "form", "fields": [{ "field": "name", "type": "text", "required": true }], "actions": [{ "label": "Submit", "action": "submit" }] }

// Math (requires u-widgets/math entry point)
{ "widget": "math", "data": { "expression": "E = mc^2" } }

// Compose
{ "widget": "compose", "layout": "grid", "children": [{ "widget": "metric", "data": { "value": 42 } }, { "widget": "gauge", "data": { "value": 73 } }] }

Chart Options

XY charts (chart.bar, chart.line, chart.area, chart.scatter) support declarative options that eliminate the need for ECharts passthrough:

Reference Lines

{
  "widget": "chart.line",
  "data": [{ "month": "Jan", "rate": 82 }, { "month": "Feb", "rate": 105 }],
  "options": {
    "referenceLines": [
      { "axis": "y", "value": 100, "label": "Target", "color": "#16a34a", "style": "dashed" }
    ]
  }
}

Per-Series Styles

{
  "widget": "chart.line",
  "data": [{ "month": "Jan", "orders": 150, "qa": 80, "support": 45 }],
  "mapping": { "x": "month", "y": ["orders", "qa", "support"] },
  "options": {
    "series": [
      { "color": "#f97316" },
      { "color": "#8b5cf6" },
      { "color": "#3b82f6", "lineStyle": { "type": "dashed" } }
    ]
  }
}

Each entry in options.series maps 1:1 to the mapping.y array. Supported overrides: color, lineStyle, symbol, label, type, yAxisIndex.

Axis Label Format

{
  "widget": "chart.bar",
  "data": [{ "month": "Jan", "revenue": 12000000 }],
  "options": {
    "yFormat": { "type": "currency", "currency": "KRW" },
    "locale": "ko-KR"
  }
}

xFormat / yFormat accept: type (number, currency, percent, date, bytes), prefix, suffix, currency, decimals.

Events

widget.addEventListener('u-widget-event', (e) => {
  console.log(e.detail); // { type, widget, id?, action?, data? }
});

MCP Server

AI assistants can use u-widgets via MCP server:

npx @iyulab/u-widgets-mcp

Framework Integration

u-widgets is a browser-only Web Component library — it requires DOM APIs (customElements, HTMLElement) and cannot run in Node.js or server-side environments.

Next.js (App Router)

Create a client-side wrapper component:

// components/widget.tsx
"use client";
import "@iyulab/u-widgets";

export function Widget({ spec }: { spec: object }) {
  return <u-widget spec={JSON.stringify(spec)} />;
}

Use the wrapper from Server Components:

// app/dashboard/page.tsx
import { Widget } from "@/components/widget";

export default async function Page() {
  const data = await fetchData();
  return <Widget spec={{ widget: "stat-group", data }} />;
}

For pages where SSR hydration mismatch is a concern, use dynamic import:

import dynamic from "next/dynamic";
const Widget = dynamic(
  () => import("@/components/widget").then((m) => m.Widget),
  { ssr: false }
);

Documentation

License

MIT

About

Declarative, data-driven web component library for data visualization and input — charts, KPIs, gauges, tables, and more with AI/MCP integration support.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages