# Brand scale

> 11 shades from 50 to 950 generated in OKLCH from one base color, copied as CSS variables.

A shadcn/ui block from the [@reui](https://reui.io) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/reui/c-color-picker-14).

- Page, with a live preview: https://shadcn.exchange/r/reui/c-color-picker-14
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/reui/c-color-picker-14-light-bfa978e905ff7860.png
- Registry item: https://reui.io/r/new-york-v4/c-color-picker-14.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://reui.io/r/new-york-v4/c-color-picker-14.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `button`, `card`, `@reui/color-picker`, `field`

## Files

### `c-color-picker-14.tsx`

```tsx
"use client"

import { useState } from "react"
import {
  ColorPicker,
  ColorPickerContent,
  ColorPickerInput,
  ColorPickerSwatch,
  formatColor,
  parseColor,
} from "@/components/reui/color-picker"
import type { ColorPickerColor } from "@/components/reui/color-picker"

import { Button } from "@/components/ui/button"
import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"
import { Field, FieldLabel } from "@/components/ui/field"

const STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]

/* Tailwind's blue scale in OKLCH: lightness per step, and chroma relative to
   500. The base color becomes 500 and the curve bends around its lightness. */
const LIGHTNESS = [
  97, 93.2, 88.2, 80.9, 70.7, 62.3, 54.6, 48.8, 42.4, 37.9, 28.2,
]
const CHROMA = [0.07, 0.15, 0.28, 0.47, 0.77, 1, 1.14, 1.14, 0.93, 0.68, 0.43]

function buildScale(base: ColorPickerColor) {
  const oklch = parseColor(formatColor(base, "oklch"))
  if (!oklch) return []
  const [lightness, chroma, hue] = oklch.channels
  return STEPS.map((step, index) => {
    const target = LIGHTNESS[index]
    const l =
      index < 5
        ? 100 - ((100 - target) * (100 - lightness)) / (100 - 62.3)
        : (target * lightness) / 62.3
    const color: ColorPickerColor = {
      space: "oklch",
      channels: [l, chroma * CHROMA[index], hue],
      alpha: 1,
    }
    return { step, value: formatColor(color, "hex") }
  })
}

export function Pattern() {
  const [base, setBase] = useState<string | null>("#7c3aed")
  const [copied, setCopied] = useState(false)
  const parsed = parseColor(base)
  const scale = parsed ? buildScale(parsed) : []
  const css = scale
    .map(({ step, value }) => `--brand-${step}: ${value};`)
    .join("\n")

  return (
    <Card className="w-full max-w-md">
      <CardHeader>
        <CardTitle>Brand scale</CardTitle>
        <CardDescription>11 shades from one base color.</CardDescription>
        <CardAction>
          <Button
            variant="outline"
            size="sm"
            disabled={!css}
            onClick={async () => {
              try {
                await navigator.clipboard.writeText(css)
                setCopied(true)
              } catch {
                setCopied(false)
              }
            }}
          >
            {copied ? "Copied" : "Copy CSS"}
          </Button>
        </CardAction>
      </CardHeader>
      <CardContent>
        <div className="flex flex-col gap-5">
          <Field>
            <FieldLabel htmlFor="brand-base">Base color</FieldLabel>
            <ColorPicker
              id="brand-base"
              value={base}
              onValueChange={(next) => {
                setBase(next)
                setCopied(false)
              }}
            >
              <ColorPickerInput />
              <ColorPickerContent />
            </ColorPicker>
          </Field>
          <ol className="grid grid-cols-11 gap-1">
            {scale.map(({ step, value }) => (
              <li key={step} className="flex flex-col items-center gap-1.5">
                <ColorPickerSwatch
                  color={value}
                  aria-label={`${step}, ${value}`}
                  className="h-10 w-full"
                />
                <span className="text-muted-foreground text-[0.625rem] tabular-nums">
                  {step}
                </span>
              </li>
            ))}
          </ol>
          <span role="status" className="sr-only">
            {copied ? "CSS variables copied" : ""}
          </span>
        </div>
      </CardContent>
    </Card>
  )
}
```
