Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/zayne-labs/ui/llms.txt

Use this file to discover all available pages before exploring further.

Zayne Labs UI is completely headless and unstyled by default, giving you full control over the visual presentation.

Headless Design

Components ship with:
  • No default styles - You decide how components look
  • Structural markup - Semantic HTML with proper accessibility
  • Data attributes - Hooks for CSS targeting
  • ClassName support - Standard React className prop on all components
This approach means:
  • Zero CSS conflicts with your existing styles
  • Complete design system flexibility
  • Smaller bundle sizes (no unused CSS)
  • Framework-agnostic styling approach

Using with Tailwind CSS

Zayne Labs UI is designed to work seamlessly with Tailwind CSS.

1. Import the Preset

The library includes a Tailwind preset with theme tokens and utilities:
style.css
@import "@zayne-labs/ui-react/css/preset.css";
The preset includes:
  • Theme variables - Color tokens like zu-foreground, zu-primary, zu-accent
  • Animations - Pre-configured transitions and keyframes
  • Utilities - Helper classes for common patterns

2. Theme Tokens

The preset defines CSS custom properties for theming:
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);
  /* ... */
}
Dark mode is automatic when using .dark class or data-theme="dark".

3. Apply Tailwind Classes

Use the className prop to style components:
import { Card } from "@zayne-labs/ui-react/ui/card";

<Card.Root className="rounded-lg border border-gray-200 bg-white shadow-sm">
  <Card.Header className="border-b border-gray-100 p-6">
    <Card.Title className="text-2xl font-bold text-zu-foreground">
      Welcome
    </Card.Title>
    <Card.Description className="mt-1 text-zu-muted-foreground">
      This card uses Tailwind classes
    </Card.Description>
  </Card.Header>
  <Card.Content className="p-6">
    Content with custom styling
  </Card.Content>
  <Card.Footer className="bg-gray-50 p-4">
    <Card.Action className="rounded-md bg-zu-primary px-4 py-2 text-zu-primary-foreground hover:opacity-90">
      Action
    </Card.Action>
  </Card.Footer>
</Card.Root>

Default Styles Example

Some components include minimal defaults that use Tailwind’s merge utility:
card.tsx
export function CardTitle<TElement extends React.ElementType = "h3">(
  props: PolymorphicProps<TElement, { className?: string }>
) {
  const { as: Element = "h3", className, ...restOfProps } = props;

  return (
    <Element
      data-slot="card-title"
      data-scope="card"
      data-part="title"
      className={cnMerge("leading-none font-semibold", className)}
      {...restOfProps}
    />
  );
}
The cnMerge utility (wraps tailwind-merge) lets you override defaults:
// Overrides font-semibold with font-bold
<Card.Title className="font-bold text-3xl">
  Custom Title
</Card.Title>

Using Without Tailwind

You can style components using vanilla CSS by targeting data attributes.

Target Data Attributes

Every component renders data-scope, data-part, and data-slot attributes:
styles.css
/* Style all card roots */
[data-scope="card"][data-part="root"] {
  border-radius: 0.5rem;
  border: 1px solid #e5e7eb;
  background: white;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

/* Style card headers */
[data-scope="card"][data-part="header"] {
  padding: 1.5rem;
  border-bottom: 1px solid #f3f4f6;
}

/* Or use the combined data-slot */
[data-slot="card-title"] {
  font-size: 1.5rem;
  font-weight: 700;
  color: #111827;
}

[data-slot="card-description"] {
  margin-top: 0.25rem;
  font-size: 0.875rem;
  color: #6b7280;
}
carousel.css
/* Base carousel container */
[data-scope="carousel"][data-part="content"] {
  position: relative;
  user-select: none;
  width: 100%;
  max-width: 800px;
}

/* Navigation buttons */
[data-slot="carousel-button"] {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 10;
  padding: 0.75rem;
  background: rgba(0, 0, 0, 0.5);
  border-radius: 50%;
  color: white;
  border: none;
  cursor: pointer;
}

[data-slot="carousel-button"]:hover {
  background: rgba(0, 0, 0, 0.7);
}

/* Indicators */
[data-slot="carousel-indicator"] button {
  width: 0.5rem;
  height: 0.5rem;
  background: rgba(255, 255, 255, 0.5);
  border-radius: 50%;
  transition: all 0.3s;
}

[data-slot="carousel-indicator"] button.active {
  width: 2rem;
  background: white;
  border-radius: 0.25rem;
}

ClassName Prop Usage

All components accept a className prop for custom styles:
// Single className
<Card.Root className="my-custom-card">

// Multiple classes
<Card.Header className="header-styles border-bottom">

// Conditional classes
<Card.Action className={isActive ? "active-button" : "inactive-button"}>

// CSS modules
import styles from "./Card.module.css";
<Card.Root className={styles.card}>

Advanced: Custom Class Name Utilities

Many components accept a classNames prop for granular control:
carousel.tsx
<Carousel.Root
  images={images}
  classNames={{
    base: "w-full max-w-4xl mx-auto",
    scrollContainer: "snap-x snap-mandatory"
  }}
>
  <Carousel.Controls
    classNames={{
      base: "absolute inset-0",
      iconContainer: "text-white bg-black/50 rounded-full p-2",
      defaultIcon: "w-6 h-6"
    }}
  />
</Carousel.Root>
This pattern is used in components with multiple internal elements that need independent styling.

Best Practices

Leverage the built-in theme tokens (zu-primary, zu-foreground, etc.) for consistency and automatic dark mode support.
// Good
<Card.Title className="text-zu-foreground" />

// Avoid hardcoding colors
<Card.Title className="text-gray-900" />
Use data attributes in your global CSS for base component styles, and className for instance-specific customization.
/* Global: All cards have this baseline */
[data-scope="card"][data-part="root"] {
  border-radius: 0.5rem;
}
{/* Instance: This specific card is special */}
<Card.Root className="border-2 border-blue-500" />
For Tailwind projects:
  • Keep component-specific utilities in your component files
  • Extract repeated patterns into custom Tailwind utilities
  • Use the @layer directive for organization
For vanilla CSS:
  • Create separate CSS files per component
  • Use CSS custom properties for theming
  • Follow BEM or a similar naming convention alongside data attributes

Next Steps

Component Structure

Learn about the compound component pattern

TypeScript

Explore type-safe component APIs

Build docs developers (and LLMs) love