# UI Components

Open source web components for every RoxyAPI domain. Drop in a natal chart, kundli wheel, panchang table, dasha timeline, tarot spread, biorhythm chart, hexagram, numerology card, or location search. Ship a finished astrology, tarot, or numerology app without writing a single line of SVG, table layout, or form code.

- **npm**: [`@roxyapi/ui`](https://www.npmjs.com/package/@roxyapi/ui), [`@roxyapi/ui-react`](https://www.npmjs.com/package/@roxyapi/ui-react)
- **CDN**: [jsDelivr](https://www.jsdelivr.com/package/npm/@roxyapi/ui), no install needed
- **shadcn registry**: per-component install for Next.js + Tailwind projects
- **Live preview**: [roxyapi.github.io/ui](https://roxyapi.github.io/ui/)
- **Source**: [github.com/RoxyAPI/ui](https://github.com/RoxyAPI/ui), MIT licensed

## Why Roxy UI

Most data APIs leave you to build the visual layer yourself. Birth charts mean SVG geometry, panchang means complex tables, dasha means timelines, tarot means card layouts and reversed-card flips. We ship the finished components so you keep your time for product work.

- **Stateless.** You fetch with the SDK, pass the response as the `data` prop, the component renders. No internal fetches, no auth, no global stores.
- **Framework agnostic.** React, Next.js, Vue, Svelte, Angular, Solid, vanilla HTML, WordPress. Same components everywhere.
- **CSS custom properties for theming.** Override 30+ tokens for color, spacing, radius, motion. Match any brand without rebuilding the bundle.
- **Accessible by default.** WAI-ARIA roles, keyboard navigation, reduced-motion gating, axe-core verified.
- **Tiny.** ~26 KB gzipped for the full bundle, ~8-10 KB per component when imported individually.
- **MIT licensed.** Use it in commercial apps. No AGPL, no copyleft, no obligations.

**Tip: Designed for the developer who is great at backend or business logic but does not want to spend a week on chart geometry, the founder who does not want to hire a UI designer for a weekend project, and the AI agent that needs to render a structured astrology response without inventing markup.**

## Pick your path

| You are building | Use this path | Time to first chart |
|---|---|---|
| Next.js, Remix, Nuxt, SvelteKit, Astro, Vue, Svelte, Angular, Solid, Qwik | **Path A**: npm + framework wrapper | ~5 min |
| Plain HTML, WordPress, Shopify theme, Stan Store, Linktree, Notion embed | **Path B**: jsDelivr CDN, no build step | ~30 seconds |
| Next.js + Tailwind + shadcn already set up | **Path C**: shadcn registry | ~5 min |

Most developers pick A or B. Path C is a Path A accelerator that drops a typed React wrapper into your repo per component.

## Path A: Next.js (and any other framework with React)

### 1. Install

```bash
npm install @roxyapi/ui-react @roxyapi/sdk
```

`@roxyapi/ui-react` ships React 19 wrappers. The underlying components load from jsDelivr at mount time so library updates ship to you without a re-install.

### 2. Set your API key

In `.env.local` at the project root:

```
ROXY_API_KEY=your_api_key_here
```

Get a key at [roxyapi.com/account](/account). Server-side use only.

**Warning: Never expose a secret API key in client-side code. Call Roxy from a server route, server action, or edge function. Anything in `NEXT_PUBLIC_*` ships to the browser and can be scraped.**

### 3. Fetch on the server, render on the client

This is the recommended Next.js App Router pattern. The Server Component fetches with your secret key, the Client Component renders the wheel.

`app/page.tsx`:

```tsx
import { createRoxy } from '@roxyapi/sdk';
import BirthChartView from './birth-chart-view';

const roxy = createRoxy(process.env.ROXY_API_KEY!);

export default async function Page() {
  const { data } = await roxy.vedicAstrology.generateBirthChart({
    body: {
      date: '1990-01-15',
      time: '14:30:00',
      latitude: 28.6139,
      longitude: 77.209,
      timezone: 5.5,
    },
  });

  return (
    <main>
      <h1>My astrology app</h1>
      <BirthChartView data={data} />
    </main>
  );
}
```

`app/birth-chart-view.tsx`:

```tsx
'use client';

import { RoxyVedicKundli } from '@roxyapi/ui-react';

export default function BirthChartView({ data }: { data: unknown }) {
  return <RoxyVedicKundli data={data} />;
}
```

### 4. Run

```bash
npm run dev
```

Open [http://localhost:3000](http://localhost:3000). The kundli renders.

**Tip: First render shows a brief blank state while the component code loads from the CDN (~26 KB gzipped). Render a skeleton or fallback while `data` is undefined for a polished feel.**

## Path B: Plain HTML (zero build step)

For a single page, an existing site, a WordPress shortcode, a Shopify theme, a Stan Store custom-code block, or a Linktree embed.

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My astrology page</title>
  <script
    src="https://cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/roxy-ui.js"
    crossorigin="anonymous"
    defer
  ></script>
</head>
<body>
  <roxy-vedic-kundli id="kundli"></roxy-vedic-kundli>

  <script type="module">
    import { createRoxy } from 'https://cdn.jsdelivr.net/npm/@roxyapi/sdk@latest/dist/factory.js';
    const roxy = createRoxy('YOUR_PUBLISHABLE_KEY');
    const { data } = await roxy.vedicAstrology.generateBirthChart({
      body: {
        date: '1990-01-15',
        time: '14:30:00',
        latitude: 28.6139,
        longitude: 77.209,
        timezone: 5.5,
      },
    });
    document.getElementById('kundli').data = data;
  </script>
</body>
</html>
```

Open the file in any browser. The kundli renders. Same pattern works in WordPress shortcodes, Shopify themes, Stan Store, Linktree, Notion, Bubble, Wix, Squarespace, or any builder that accepts custom HTML.

**Warning: For browser-side calls, use a publishable key (`pk_live_*` / `pk_test_*`), not a secret key. Publishable keys are origin-restricted at the API gateway, so a leaked key from another domain returns 403 instead of burning your quota. Get one at [roxyapi.com/account](/account) and register the domains you embed on.**

### Pin the version in production

Marketing snippets use `@latest`. Production code should pin to a concrete version so a CDN update never surprises you.

```html
<script src="https://cdn.jsdelivr.net/npm/@roxyapi/ui@0/dist/cdn/roxy-ui.js"></script>
```

## Path C: shadcn registry (Next.js + Tailwind)

Already running shadcn? Install per-component. Each entry drops a typed React wrapper into `components/roxy-ui/{name}.tsx` and merges the CSS variable theme bridge into your `globals.css` so your existing shadcn theme drives Roxy components automatically.

```bash
npx shadcn@latest add https://cdn.jsdelivr.net/gh/RoxyAPI/ui@latest/registry/vedic-kundli.json
```

Use the wrapper:

```tsx
import { RoxyVedicKundli } from '@/components/roxy-ui/vedic-kundli';

export default async function Page() {
  const data = await fetchKundliFromYourServer();
  return <RoxyVedicKundli data={data} />;
}
```

The wrapper file is a starter you own. Open it and customize freely.

**Tip: Roxy components install under `components/roxy-ui/`, not `components/ui/`. Your shadcn `button.tsx`, `card.tsx`, `input.tsx` stay untouched.**

## What you can render

Every component takes a typed response from the matching endpoint. Pass the SDK response, the component figures out the rest.

| Component | Domain | What it renders |
|---|---|---|
| `<roxy-natal-chart>` | Western astrology | Natal chart wheel with planet glyphs and aspect lines |
| `<roxy-horoscope-card>` | Western astrology | Daily, weekly, or monthly horoscope card |
| `<roxy-synastry-chart>` | Western astrology | Dual-wheel synastry plus inter-aspects table |
| `<roxy-moon-phase>` | Western astrology | Moon phase card and calendar grid |
| `<roxy-vedic-kundli>` | Vedic astrology | South or North Indian kundli layout |
| `<roxy-panchang-table>` | Vedic astrology | Tithi, vara, nakshatra, yoga, karana, plus muhurtas |
| `<roxy-dasha-timeline>` | Vedic astrology | Vimshottari mahadasha plus antardasha plus pratyantardasha |
| `<roxy-dosha-card>` | Vedic astrology | Manglik, Kalsarpa, Sade Sati severity, exceptions, remedies |
| `<roxy-guna-milan>` | Vedic astrology | 36-point Ashtakoota with eight Koot sub-scores |
| `<roxy-kp-planets-table>` | Vedic (KP system) | KP planets with sub-lord and sub-sub-lord columns |
| `<roxy-numerology-card>` | Numerology | Life Path, Expression, Personal Year, full chart |
| `<roxy-tarot-card>` | Tarot | Single card with upright and reversed flip |
| `<roxy-tarot-spread>` | Tarot | Three-card, Celtic Cross, love, career spreads |
| `<roxy-biorhythm-chart>` | Biorhythm | Daily bars, multi-day forecast, critical days |
| `<roxy-hexagram>` | I Ching | Hexagram with trigrams, judgment, image, changing lines |
| `<roxy-compatibility-card>` | Cross-domain | Score card with category breakdown |
| `<roxy-location-search>` | Helper | Debounced city search, fires `roxy-location-select` event |
| `<roxy-endpoint-form>` | Helper | Schema-driven form for any endpoint |

Full live preview of every component at [roxyapi.github.io/ui](https://roxyapi.github.io/ui/). Click any component for a Preview tab and a copy-paste Code tab.

## Theming

Every component reads from CSS custom properties on `:root`. Override globally to match your brand.

```css
:root {
  --roxy-bg: #fafafa;
  --roxy-fg: #0a0a0a;
  --roxy-muted: #71717a;
  --roxy-border: #e4e4e7;

  --roxy-accent: #f59e0b;
  --roxy-accent-fg: #b45309;

  --roxy-radius-md: 12px;
  --roxy-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
  --roxy-motion-duration: 200ms;
}

[data-theme="dark"] {
  --roxy-bg: #0a0a0a;
  --roxy-fg: #fafafa;
  --roxy-muted: #a1a1aa;
  --roxy-border: #27272a;
}
```

Or override per element to deviate one component without touching the rest:

```css
roxy-natal-chart {
  --roxy-accent: #ec4899;
  --roxy-radius-md: 8px;
}
```

The live preview at [roxyapi.github.io/ui](https://roxyapi.github.io/ui/) has a Customize button (top right) that visualizes every token and outputs a CSS block you paste into your project.

### Already on shadcn?

Path C installs a thin bridge that maps your existing shadcn `--background`, `--foreground`, `--primary`, `--border`, `--radius` onto the Roxy variables. Your shadcn theme drives Roxy components automatically. Path A and Path B users can ship the same bridge as a small CSS file:

```css
@layer base {
  :root {
    --roxy-bg: var(--background, #fafafa);
    --roxy-fg: var(--foreground, #0a0a0a);
    --roxy-accent: var(--primary, #f59e0b);
    --roxy-border: var(--border, #e4e4e7);
    --roxy-radius-md: var(--radius, 12px);
  }
}
```

## Wiring custom events

Some components dispatch typed events: `roxy-submit`, `roxy-location-select`, `roxy-validation-error`. The React wrappers expose them as handler props.

```tsx
import { RoxyLocationSearch } from '@roxyapi/ui-react';

<RoxyLocationSearch
  onRoxyLocationSelect={(e) => {
    console.log(e.detail.latitude, e.detail.longitude, e.detail.timezone);
  }}
/>
```

In vanilla HTML, listen the standard way:

```html
<roxy-location-search id="search"></roxy-location-search>
<script>
  document.getElementById('search').addEventListener('roxy-location-select', (e) => {
    console.log(e.detail.latitude, e.detail.longitude, e.detail.timezone);
  });
</script>
```

## Common gotchas


### `[object Object]` in the rendered chart
You passed the SDK envelope instead of the unwrapped response.

Wrong:
```ts
const response = await roxy.vedicAstrology.generateBirthChart({...});
element.data = response;
```

Right:
```ts
const { data } = await roxy.vedicAstrology.generateBirthChart({...});
element.data = data;
```

The SDK returns `{ data, error, request, response }`. Always destructure `data`.

### "Loading..." that never resolves
The API call is failing silently. Open the network tab and check the status code.

- 401 `api_key_required`: pass your key to `createRoxy(...)`.
- 401 `invalid_api_key`: typo in the key.
- 403 `origin_not_allowed`: publishable key called from an origin not in its allowlist. Add the origin at [roxyapi.com/account](/account).
- 429 `rate_limit_exceeded`: monthly quota burned. Quota resets on the 1st.

### `'use client'` errors in Next.js App Router
The wrappers use the DOM. Add `'use client'` at the top of any file that imports from `@roxyapi/ui-react`. Server Components cannot import them directly. The recommended pattern is "fetch in a Server Component, render in a small Client Component" (see Path A).

### Empty page on first paint
Expected. The wrapper loads the component code from the CDN (~26 KB gzipped) on mount. Render a fallback while data is null, or preload the bundle in your `<head>`:

```tsx
<link
  rel="preload"
  as="script"
  crossOrigin="anonymous"
  href="https://cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/roxy-ui.js"
/>
```

### Components work locally but break on GitHub Pages or any sub-path host
You used origin-absolute paths (`/something`). Use relative paths (`./something`) or set `<base href="./">`.

### Tarot card images return CORS errors
The component reads `imageUrl` from the response. Either serve those images from your own CDN, or set `Cross-Origin-Resource-Policy: cross-origin` on your image host.

### React 17 or 18 ignores hyphenated event names
Upgrade to React 19 if you can. If you cannot, bind manually with `addEventListener` in `useEffect` instead of using the `onRoxy*` props.

## Verification checklist

After integrating, confirm:

- [ ] No `[object Object]` strings in any chart, table, or card.
- [ ] No "Loading..." that never resolves.
- [ ] Browser console has no errors and no warnings.
- [ ] Dark mode flips when you toggle `[data-theme="dark"]` on `<html>`.
- [ ] Production build (`npm run build`) compiles without errors.
- [ ] The key in any client-bundled code is a publishable key, not a secret one.

## Where to go next

- **Live customizer** at [roxyapi.github.io/ui](https://roxyapi.github.io/ui/). Theme tokens, copy-paste integration snippets, every component rendered against real responses.
- **Source code** at [github.com/RoxyAPI/ui](https://github.com/RoxyAPI/ui). MIT licensed. Issues, contributions, and release notes welcome.
- **Catalog page** at [roxyapi.com/ui](/ui) for distribution surfaces and FAQ.
- **SDK reference** at [/docs/sdk](/docs/sdk) for every endpoint method.
- **Get an API key** at [roxyapi.com/pricing](/pricing). Instant delivery, no approval queue.

## Frequently asked questions


### Is Roxy UI really free?
Yes. MIT licensed. Use it in commercial apps.

### Can I use it without the SDK?
Yes. Components are stateless. Fetch with `fetch`, axios, your favorite client, your own server proxy, anything. Pass the response as the `data` prop.

### Does it support React Native or Flutter?
Not yet. Web (browsers and webviews) only as of 2026.

### Will my brand colors work?
Yes. Override the `--roxy-*` CSS custom properties on `:root` or per element. The live preview has a Customize button that exports a CSS block.

### Do I need a separate UI/UX designer?
No. The components ship with sensible defaults out of the box. Theme to your brand colors and you are done.

### Can AI coding agents use this?
Yes. Cursor, Claude Code, GitHub Copilot, Codex, and any agent reading your `package.json` will see `@roxyapi/ui` and the standard component names. Path C drops typed wrapper files into your repo, which makes agent navigation even easier.

### How big is the bundle?
~26 KB gzipped for the full bundle from the CDN. ~8-10 KB per component when imported individually via the framework wrappers.

### Is there a TypeScript type for the response shape?
Yes. The SDK ships full types. The component `data` prop is typed against the matching endpoint response. Your IDE catches schema drift before runtime.

### What if my endpoint is not in the component list?
The catch-all `<roxy-data>` element renders any response shape as a structured table. New endpoints work out of the box; bespoke components ship as the catalog grows.
