Introduction
@anxndsgn/ink-ui

Why Ink UI?

  • Ink UI is a React component library built on top of Base UI primitives and styled with Tailwind CSS v4. which provides a solid foundation of accessible and customizable components.
  • The design focuses on warmth and approachability, with a color palette built around warm grays and oranges, and large rounded corners. The goal is to create interfaces that feel more human and inviting. It is not suited for very professional or complex dashboard-style interfaces, but rather for less complex, consumer-facing products that want to convey a sense of friendliness and delight.
  • The motion system emphasizes smooth, natural transitions with a focus on micro-interactions that add delight without overwhelming the user. Subtle easing and thoughtful timing are used to create a sense of responsiveness and polish.

Prerequisites

Before using Ink UI components, ensure your project is set up with:

  • React 19
  • Tailwind CSS 4
  • @base-ui/react

Installation

1. Add Tailwind and Base UI

Follow the Tailwind CSS v4 installation guide and the Base UI quick start for your framework.

2. Copy the theme

Copy the CSS variables into your global stylesheet. These define the warm color palette and semantic tokens used by all components.

@theme {
/* gray */
--color-gray-50: oklch(0.98559 0.002 48.697);
--color-gray-100: oklch(0.95 0.001 48.697);
--color-gray-200: oklch(0.925 0.002 48.697);
--color-gray-300: oklch(0.84598 0.002 48.697);
--color-gray-400: oklch(0.7374 0.002 48.697);
--color-gray-500: oklch(0.585 0.003 48.697);
--color-gray-600: oklch(0.46 0.002 48.697);
--color-gray-700: oklch(0.37 0.002 48.697);
--color-gray-800: oklch(0.31 0.001 48.697);
--color-gray-900: oklch(0.265 0.001 48.697);
--color-gray-950: oklch(0.21 0.002 48.697);

/_ red _/
--color-red-50: oklch(0.96453 0.015 24);
--color-red-100: oklch(0.95036 0.03 24);
--color-red-200: oklch(0.92601 0.045 24);
--color-red-300: oklch(0.8455 0.07 24);
--color-red-400: oklch(0.73813 0.135 24);
--color-red-500: oklch(0.63497 0.18 24);
--color-red-600: oklch(0.50144 0.15 24);
--color-red-700: oklch(0.38998 0.125 24);
--color-red-800: oklch(0.30985 0.095 24);
--color-red-900: oklch(0.26461 0.06 24);
--color-red-950: oklch(0.21016 0.04 24);

/_ orange _/
--color-orange-50: oklch(0.96453 0.02 41.5);
--color-orange-100: oklch(0.95036 0.025 41.5);
--color-orange-200: oklch(0.92601 0.03 41.5);
--color-orange-300: oklch(0.8455 0.07 41.5);
--color-orange-400: oklch(0.73813 0.14 41.5);
--color-orange-500: oklch(0.63497 0.17 41.5);
--color-orange-600: oklch(0.50144 0.135 41.5);
--color-orange-700: oklch(0.38998 0.08 41.5);
--color-orange-800: oklch(0.30985 0.065 41.5);
--color-orange-900: oklch(0.26461 0.055 41.5);
--color-orange-950: oklch(0.21016 0.04 41.5);
}

:root {
--background: oklch(0.98559 0.002 48.697);
--foreground: oklch(0.265 0.001 48.697);
--card: oklch(0.95 0.001 48.697);
--card-foreground: oklch(0.265 0.001 48.697);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.265 0.001 48.697);
--dialog: oklch(0.98559 0.002 48.697);
--dialog-foreground: oklch(0.265 0.001 48.697);
--primary: oklch(0.265 0.001 48.697);
--primary-foreground: oklch(1 0 0);
--secondary: oklch(0.21 0.002 48.697 / 0.08);
--secondary-foreground: oklch(0.265 0.001 48.697);
--muted: oklch(0.95 0.001 48.697);
--muted-foreground: oklch(0.585 0.003 48.697);
--accent: oklch(0.63497 0.17 41.5);
--accent-foreground: oklch(1 0 0);
--destructive: oklch(0.63497 0.18 24);
--destructive-foreground: oklch(1 0 0);
--border: oklch(0.21 0.002 48.697 / 0.1);
--input: oklch(0.21 0.002 48.697 / 0.1);
--ring: oklch(0.63497 0.17 41.5 / 0.3);
}

[data-mode="dark"] {
--background: oklch(0.21 0.002 48.697);
--foreground: oklch(0.95 0.001 48.697);
--card: oklch(0.21 0.002 48.697);
--card-foreground: oklch(0.95 0.001 48.697);
--popover: oklch(0.265 0.001 48.697);
--popover-foreground: oklch(0.95 0.001 48.697);
--dialog: oklch(0.265 0.001 48.697);
--dialog-foreground: oklch(0.95 0.001 48.697);
--primary: oklch(0.95 0.001 48.697);
--primary-foreground: oklch(0.265 0.001 48.697);
--secondary: oklch(0.98559 0.002 48.697 / 0.08);
--secondary-foreground: oklch(0.95 0.001 48.697);
--muted: oklch(0.31 0.001 48.697);
--muted-foreground: oklch(0.7374 0.002 48.697);
--accent: oklch(0.50144 0.135 41.5);
--accent-foreground: oklch(1 0 0);
--destructive: oklch(0.63497 0.18 24);
--destructive-foreground: oklch(1 0 0);
--border: oklch(0.98559 0.002 48.697 / 0.1);
--input: oklch(0.98559 0.002 48.697 / 0.1);
--ring: oklch(0.63497 0.17 41.5 / 0.3);
}

@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-dialog: var(--dialog);
--color-dialog-foreground: var(--dialog-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
}

See the Colors page for a full reference of all available tokens and scales.

3. Add utilities

Copy the cn helper into your project:

import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

4. Copy components

Browse the Components section and copy any component source into your project. Each component is a self-contained file with no hidden dependencies.

Dark mode

Dark mode is toggled by setting the data-mode="dark" attribute on the <html> element. All semantic tokens automatically adapt between light and dark contexts.