# Title: Component Structure Description: Understanding the compound component pattern, asChild, polymorphism, and data attributes in Zayne UI URL: /docs/component-structure Source: https://raw.githubusercontent.com/zayne-labs/callapi/refs/heads/main/apps/docs/content/docs/component-structure.mdx Zayne UI uses a **compound component pattern** — a single import gives you a namespace of sub-components that work together, sharing state through React context without prop drilling. ## Compound components [#compound-components] Instead of one monolithic component with dozens of props, Zayne UI splits each component into composable parts. You pick the parts you need and arrange them however you want: ```tsx import { DropZone } from "@zayne-labs/ui-react/ui/drop-zone";

Drag and drop files here

Select Files
{({ fileState }) => ( Remove )}
; ``` Each sub-component is independently renderable. You can omit `DropZone.FileList` if you don't need file previews, or omit `DropZone.Trigger` if you only want drag-and-drop with no click-to-browse. ## Import patterns [#import-patterns] Every component supports **two** import styles: The namespace import gives you dot-notation access to all sub-components: ```tsx import { DropZone } from "@zayne-labs/ui-react/ui/drop-zone"; import { Show } from "@zayne-labs/ui-react/common/show"; ... ... ``` This is the recommended approach — it keeps component families visually grouped and makes it clear which parts belong together. If you prefer, you can import each sub-component by its full name: ```tsx import { DropZoneRoot, DropZoneTrigger, DropZoneArea } from "@zayne-labs/ui-react/ui/drop-zone"; import { ShowRoot, ShowContent, ShowFallback } from "@zayne-labs/ui-react/common/show"; Browse ``` ## The `as` prop — polymorphism [#the-as-prop--polymorphism] Most components accept an `as` prop that changes the underlying HTML element. TypeScript enforces that only valid attributes for the chosen element are allowed: ```tsx import { Card } from "@zayne-labs/ui-react/ui/card"; // Default — renders
Content; // Renders with full anchor props Clickable Card ; // Renders
Stats ; ``` Each Card sub-component has its own default element: | Sub-component | Default element | Accepts `as` | | :----------------- | :-------------- | :----------- | | `Card.Root` | `
` | ✅ | | `Card.Header` | `
` | ✅ | | `Card.Title` | `

` | ✅ | | `Card.Description` | `

` | ✅ | | `Card.Content` | `

` | ✅ | | `Card.Action` | `
)} {(user) => (

{user.name}

{user.email}

)}
); } ``` ## Next steps [#next-steps] * **[Component Structure](/docs/component-structure)** — Learn the compound component pattern, `asChild`, and data attributes * **[Styling](/docs/styling)** — Tailwind CSS preset, vanilla CSS targeting, and the `unstyled` prop * **[TypeScript](/docs/typescript)** — Type inference, polymorphic props, and discriminated unions # Title: Styling Description: Learn how to style Zayne UI components with Tailwind CSS, vanilla CSS, or any approach you prefer URL: /docs/styling Source: https://raw.githubusercontent.com/zayne-labs/callapi/refs/heads/main/apps/docs/content/docs/styling.mdx Zayne UI is headless — components ship with **zero visual styling** by default. A few components include minimal structural CSS (e.g., flexbox layout on `DragScroll.List`), but everything visual is yours to define. You have three tools for styling: 1. **`className`** — Add classes to any component, just like a native element 2. **`unstyled`** — Opt out of even the minimal structural styles on a per-component basis 3. **Data attributes** — Target components from external CSS via `data-scope`, `data-part`, and `data-slot` ## Using with Tailwind CSS v4 [#using-with-tailwind-css-v4] Zayne UI includes an optional Tailwind CSS v4 preset. Import it in your global CSS as shown in the [Installation Guide](/docs/installation): ```css title="app/globals.css" @import "tailwindcss"; @import "@zayne-labs/ui-react/css/preset.css"; ``` ### Theme tokens [#theme-tokens] The preset registers CSS custom properties scoped under `zu-*` that you can use throughout your project: ```css title="@zayne-labs/ui-react/css/theme.css" @theme { --color-zu-foreground: oklch(0.145 0 0); --color-zu-accent: oklch(0.967 0.001 286.375); --color-zu-accent-foreground: oklch(0.205 0 0); --color-zu-muted-foreground: oklch(0.556 0 0); --color-zu-destructive: oklch(0.577 0.245 27.325); --color-zu-primary: oklch(0.21 0.04 265.75); --color-zu-primary-foreground: oklch(0.985 0 0); --color-zu-ring: oklch(0.705 0.015 286.067); } :where(.dark, [data-theme="dark"]) { --color-zu-foreground: oklch(0.985 0 0); --color-zu-primary: oklch(0.92 0.004 286.32); /* ... */ } ``` Use these tokens in your Tailwind classes: ```tsx ``` Dark mode activates automatically with the `.dark` class or `data-theme="dark"` attribute on any ancestor element. ### Animations [#animations] The preset includes named animations used by components internally, but you can also use them directly: | Token | Description | Used by | | :--------------------- | :-------------------------- | :------------------ | | `animate-shake` | Error shake / jiggle effect | `Form.ErrorMessage` | | `animate-fade-up` | Fade in from below | General use | | `animate-fade-down` | Fade in from above | General use | | `animate-files-in` | File item entry animation | `DropZone.FileItem` | | `animate-progress-out` | Progress bar exit animation | `DropZone` progress | ### Utilities [#utilities] The preset adds a `scrollbar-hidden` utility that hides scrollbars across all browsers while keeping the content scrollable: ```tsx ``` ### Styling example [#styling-example] Here's a fully styled `DropZone` using Tailwind and the preset tokens: ```tsx import { DropZone } from "@zayne-labs/ui-react/ui/drop-zone";

Drop files here

Select Files
; ``` Notice how `data-drag-over:` targets the `data-drag-over` attribute that `DropZone.Area` sets automatically when files are hovering. ## The `unstyled` prop [#the-unstyled-prop] Some UI components apply minimal structural CSS by default (like flex layout, cursor styles, or scrollbar hiding). If you want full control, pass `unstyled` to remove those base styles: ```tsx /* Default — includes structural CSS (e.g., display:flex, cursor:grab) */ ; /* Unstyled — no structural CSS at all, you define everything */ ; ``` The `unstyled` prop is available on UI component parts that have base styles (like `DragScroll.Root`, `DragScroll.List`, `DragScroll.Prev`, `DragScroll.Next`). Utility components have no base styles, so they don't need it. ## Using without Tailwind [#using-without-tailwind] ### Pre-compiled styles [#pre-compiled-styles] If you're not using Tailwind, import the compiled CSS bundle in your entry file: ```css title="app/globals.css" @import "@zayne-labs/ui-react/style.css"; ``` ### Vanilla CSS via data attributes [#vanilla-css-via-data-attributes] Every component renders three data attributes for CSS targeting. This means you never need to rely on internal class names or DOM structure: | Attribute | Description | Example values | | :----------- | :------------------------------ | :-------------------------------------- | | `data-scope` | Identifies the component family | `"card"`, `"dropzone"`, `"drag-scroll"` | | `data-part` | Identifies the specific part | `"root"`, `"area"`, `"title"`, `"list"` | | `data-slot` | Combined scope + part | `"card-header"`, `"drag-scroll-list"` | Use them to style components from a standalone CSS file: ```css title="styles.css" /* Target a specific component part */ [data-scope="drag-scroll"][data-part="list"] { display: flex; gap: 1rem; overflow-x: auto; cursor: grab; scrollbar-width: none; /* Firefox */ } [data-scope="drag-scroll"][data-part="list"]:active { cursor: grabbing; } /* Or use the combined slot for shorter selectors */ [data-slot="drag-scroll-list"] { scrollbar-width: none; } /* Target stateful attributes */ [data-scope="drag-scroll"][data-part="list"][data-dragging="true"] { cursor: grabbing; user-select: none; } [data-scope="drop-zone"][data-part="area"][data-drag-over] { border-color: var(--color-zu-primary); background: oklch(0.97 0.01 265); } ``` Using `data-slot` is a convenient shorthand when you don't need the specificity of `data-scope` + `data-part`. Both approaches target the same elements. ### Stateful data attributes [#stateful-data-attributes] Many components set additional data attributes to reflect their current state. These are documented on each component's page, but here's a summary of the most useful ones: | Attribute | Component(s) | Description | | :---------------------- | :------------------------ | :--------------------------------------------------- | | `data-dragging` | `DragScroll.List` | `"true"` when the user is actively dragging | | `data-disabled` | `DragScroll.Prev/Next` | `"true"` when there's nothing more to scroll | | `data-drag-over` | `DropZone.Area` | Present when files are hovering over the zone | | `data-invalid` | `DropZone.Area`, `Form.*` | Present when validation fails | | `data-status` | `DropZone.FileItem` | `"idle"`, `"uploading"`, `"success"`, or `"error"` | | `data-state` | `DropZone.FileList` | `"active"` when files exist, `"inactive"` when empty | | `data-animation-phase` | `Presence` child | `"enter"` or `"exit"` (animation variant) | | `data-transition-phase` | `Presence` child | `"enter"` or `"exit"` (transition variant) | | `data-mounted` | `Presence` child | Whether the element is currently mounted | # Title: TypeScript Description: Full type safety and inference — zero manual annotations needed URL: /docs/typescript Source: https://raw.githubusercontent.com/zayne-labs/callapi/refs/heads/main/apps/docs/content/docs/typescript.mdx Zayne UI is written in TypeScript and designed so that types flow through your code automatically. You rarely need to annotate anything manually. ## Automatic type inference [#automatic-type-inference] ### The `For` component [#the-for-component] `For` infers item types from whatever you pass to `each`. The render function receives the correct type — including the `index` and full `array` parameters: ```tsx const products = [ { id: 1, name: "Laptop", price: 999 }, { id: 2, name: "Mouse", price: 29 }, ]; {(product, index, array) => (
{/* ✅ product is typed as { id: number; name: string; price: number } */} {product.name} - ${product.price} {/* ❌ TS error: Property 'details' does not exist */} {product.details}
)}
; ``` When you pass a number, the render function receives `number` for both the item and index: ```tsx {(index) =>
} ``` ### The `Show` component — type narrowing [#the-show-component--type-narrowing] `Show` narrows nullable types when you use the render function pattern. Inside the callback, TypeScript knows the value is non-null: ```tsx const user: User | null = getUser(); // Without Show — you'd need to assert or check manually {(activeUser) => ( // ✅ activeUser is typed as User (not User | null)

{activeUser.name}

{activeUser.email}

)}
; ``` This also works inside `Show.Content` when using `control="content"` mode: ```tsx {(err) => ( // ✅ err is typed as Error (not Error | null | undefined)

{err.message}

)}
``` ### The `Switch` component — render prop narrowing [#the-switch-component--render-prop-narrowing] `Switch.Match` supports render functions that receive the narrowed `when` value: ```tsx type ApiResponse = { data: User[] } | null; const response: ApiResponse = fetchData(); Loading... {(result) => ( // ✅ result is typed as { data: User[] } (not null) )} No data ; ``` ### The `Await` component — promise result inference [#the-await-component--promise-result-inference] `Await.Success` automatically infers the resolved type of the promise: ```tsx const userPromise: Promise<{ email: string; name: string }> = fetchUser(id); {(user) => ( // ✅ user is typed as { name: string; email: string }

{user.name} ({user.email})

)}
{({ error, resetErrorBoundary }) => ( // ✅ error is typed as Error, resetErrorBoundary is a function )}
; ``` ## Discriminated unions [#discriminated-unions] Several components use TypeScript discriminated unions to provide different prop shapes depending on the mode. The compiler prevents you from mixing incompatible props. ### `Show` — `control` prop [#show--control-prop] When `control` is `"root"` (the default), you must provide `when`. When `control` is `"content"`, `when` is forbidden on the root — it belongs on `Show.Content` instead: ```tsx <> {/* ✅ control="root" (default) — `when` is required */} }> {(u) => } {/* ✅ control="content" — `when` goes on each Content branch */} Branch A Branch B {/* ❌ TS error: `when` is not allowed when control="content" */} ... ``` ### `ErrorBoundary` — `onErrorReset` context [#errorboundary--onerrorreset-context] The `onErrorReset` callback receives a discriminated union that tells you *why* the boundary reset: ```tsx { if (context.reason === "keys") { // ✅ context.prev and context.next are available console.log("Reset because keys changed:", context.prev, "→", context.next); } if (context.reason === "imperative-api") { // ✅ context.args is available (from resetErrorBoundary(...args)) console.log("Reset manually with args:", context.args); } }} > ``` ## Polymorphic components [#polymorphic-components] Most UI components accept an `as` prop to change the rendered HTML element. TypeScript enforces that only valid props for the chosen element are allowed: ```tsx import { Card } from "@zayne-labs/ui-react/ui/card"; <> {/* Default — renders
*/} Content {/* Renders
— no additional props needed */} Content {/* Renders — TypeScript requires href */} Clickable Card {/* ❌ TS error: 'href' does not exist on type 'div' */} Invalid ; ``` `ForWithWrapper` is also polymorphic — you can change the container element: ```tsx import { ForWithWrapper } from "@zayne-labs/ui-react/common/for"; /* Renders
    instead of the default
      */ {(item) =>
    • {item.label}
    • }
      ; /* Renders for table rows */ {(row) => ( {row.label} {row.value} )} ; ``` ## Exported types [#exported-types] All component prop types are exported for when you need to type wrapper components or accept props as parameters: ```tsx // Utility component types import type { ForProps, ShowContentProps, ShowRootProps } from "@zayne-labs/ui-react/common"; import type { ErrorBoundaryProps } from "@zayne-labs/ui-react/common/error-boundary"; import type { PresenceProps } from "@zayne-labs/ui-react/common/presence"; import type { SwitchMatchProps, SwitchRootProps } from "@zayne-labs/ui-react/common/switch"; // UI component types import type { CardRootProps } from "@zayne-labs/ui-react/ui/card"; import type { DragScrollRootProps } from "@zayne-labs/ui-react/ui/drag-scroll"; import type { FormRootProps } from "@zayne-labs/ui-react/ui/form"; ``` ## Recommended TypeScript config [#recommended-typescript-config] For React 19 projects, use this baseline configuration: ```json title="tsconfig.json" { "compilerOptions": { "moduleResolution": "bundler", "jsx": "react-jsx", "strict": true } } ``` `"moduleResolution": "bundler"` is required for Zayne UI's per-component entry points (e.g., `@zayne-labs/ui-react/common/show`) to resolve correctly. The older `"node"` resolution does not support subpath exports. # Title: Card Description: A flexible container component for grouping related content with optional header, footer, and action sections. URL: /docs/ui/card Source: https://raw.githubusercontent.com/zayne-labs/callapi/refs/heads/main/apps/docs/content/docs/ui/card.mdx A container component that groups related content and actions. It splits the layout into distinct sections like headers, main content, and footers, letting you arrange each part independently. ## Installation [#installation] npm pnpm yarn bun ```bash npm install @zayne-labs/ui-react ``` ```bash pnpm add @zayne-labs/ui-react ``` ```bash yarn add @zayne-labs/ui-react ``` ```bash bun add @zayne-labs/ui-react ``` ## Preview [#preview] ## Basic Usage [#basic-usage] ```tsx import { Card } from "@zayne-labs/ui-react/ui/card"; Account Overview Manage your profile and settings

      View and update your personal information, security settings, and preferences.

      Edit Profile
      ; ``` ## Component Source [#component-source] ## Component API [#component-api] All Card components are polymorphic and support the `asChild` pattern. * `Card.Root` - Primary container (renders `
      ` by default) * `Card.Header` - Container for titles and descriptions (renders `
      `) * `Card.Title` - Title element (renders `

      `) * `Card.Description` - Description element (renders `

      `) * `Card.Content` - Main content area (renders `

      `) * `Card.Action` - Interactive element (renders `
      }> {() => (
      Window width: {window.innerWidth}px
      )} ); } ``` ## Component Source [#component-source] ## Component API [#component-api] ## Why use ClientGate? [#why-use-clientgate] * **Zero Hydration Mismatches**: Guarantees the server HTML and client initial render are identical (or correctly deferred). * **Safe Browser Access**: Safely access `window`, `localStorage`, or `document` within the children. * **Improved CLS**: By providing a matching fallback, you can maintain Cumulative Layout Shift scores. ```tsx // ❌ Dangerous (causes mismatch or crash) const isDesktop = window.innerWidth > 1024; // ✅ Safe with ClientGate }> ; ``` Content inside a `ClientGate` is **invisible to search engines** and SEO bots because it only appears after hydration. Use it sparingly for non-critical UI elements or interactive widgets. # Title: ErrorBoundary Description: Catch and handle React component errors with declarative error boundaries. URL: /docs/utility/error-boundary Source: https://raw.githubusercontent.com/zayne-labs/callapi/refs/heads/main/apps/docs/content/docs/utility/error-boundary.mdx The `ErrorBoundary` component catches JavaScript errors anywhere in its child component tree, logs the error, and displays a fallback UI instead of crashing the entire application. ## Installation [#installation] npm pnpm yarn bun ```bash npm install @zayne-labs/ui-react ``` ```bash pnpm add @zayne-labs/ui-react ``` ```bash yarn add @zayne-labs/ui-react ``` ```bash bun add @zayne-labs/ui-react ``` ## Preview [#preview] ## Basic Usage [#basic-usage] Provide a static component or element to display when an error occurs. ```tsx import { ErrorBoundary } from "@zayne-labs/ui-react/common/error-boundary"; function App() { return ( Something went wrong

}> ); } ``` Use a render function to access the error details and provide a way to reset the boundary. ```tsx import { ErrorBoundary } from "@zayne-labs/ui-react/common/error-boundary"; function App() { return ( (

Unexpected Error

{error.message}
)} >
); } ```
## Component Source [#component-source] ## Component API [#component-api] Provides access to the error boundary's state and methods for functional components. ## Best Practices [#best-practices] * **Isolate Failures**: Place boundaries around specific widgets or sections (like a sidebar or a feed) to prevent a single component failure from breaking the whole page. * **Auto-Reset**: Use `resetKeys` with URL params or resource IDs so that navigating away and back "fixes" the component if it crashed. * **Global Boundary**: Keep a generic boundary at the very top of your app as a last resort. Error boundaries do **not** catch errors in event handlers or asynchronous code (like `setTimeout`) by default. Use the `showBoundary` method from `useErrorBoundary` to catch these manually. # Title: For Description: Declarative list rendering with built-in empty state handling for cleaner JSX. URL: /docs/utility/for Source: https://raw.githubusercontent.com/zayne-labs/callapi/refs/heads/main/apps/docs/content/docs/utility/for.mdx The `For` component provides a declarative way to render lists and arrays in React, with automatic empty state handling and support for numeric ranges. ## Installation [#installation] npm pnpm yarn bun ```bash npm install @zayne-labs/ui-react ``` ```bash pnpm add @zayne-labs/ui-react ``` ```bash yarn add @zayne-labs/ui-react ``` ```bash bun add @zayne-labs/ui-react ``` ## Preview [#preview] ## Usage [#usage] Pass an array to `each` and utilize the render prop to define your items. ```tsx import { For } from "@zayne-labs/ui-react/common/for"; function UserList({ users }) { return ( No users joined yet.

}> {(user) => (
{user.name}
)}
); } ```
Pass a number to `each` to repeat content a specific number of times. Perfect for skeletons! ```tsx import { For } from "@zayne-labs/ui-react/common/for"; function TableSkeleton() { return ( {(i) => (
)} ); } ``` Use `renderItem` prop for cleaner syntax when you need to pass the render function as a prop. ```tsx import { ForWithWrapper } from "@zayne-labs/ui-react/common/for"; function ProductGrid({ products }) { return ( (
  • {product.name}

    ${product.price}

  • )} /> ); } ```
    ## Component Source [#component-source] ## Component API [#component-api] The standard iteration component that renders children directly into the parent. Renders items within a specific container element (e.g., `