Mohamed Uvaish

Color Picker

Forms 5

About

Brand colour picker on react-colorful: saturation area, hue slider, swatches and a hex field that expands shorthand ("1ba" → #11bbaa) and ignores invalid input. Opens from a Field. Part of the Layro System: layro.vercel.app.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Color Picker to your project and fits it to your theme.

Code

How Color Picker is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

import * as React from "react";
import { ColorPicker, Field } from "@/components/ui/color-picker-hex-swatches";
import { AlertTriangle, Check, FileSignature } from "lucide-react";

/* A brand theme editor. Drag in the square, pick a swatch, or type a hex:
   "1ba" expands to #11bbaa and an invalid value never reaches your state.
   The signing page on the right repaints as you change a colour, picks black
   or white text for it, and reports the contrast ratio. */

function luminance(hex: string) {
  const n = parseInt(hex.slice(1), 16);
  const [r, g, b] = [(n >> 16) & 255, (n >> 8) & 255, n & 255].map((v) => {
    const c = v / 255;
    return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
  });
  return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
/* whichever of white and near-black reads better on the colour, and by how much */
function readable(hex: string) {
  const L = luminance(hex);
  const onWhite = 1.05 / (L + 0.05);
  const onBlack = (L + 0.05) / 0.0556;
  return onWhite >= onBlack ? { ink: "#ffffff", ratio: onWhite } : { ink: "#111111", ratio: onBlack };
}

const BRAND = ["#2563eb", "#1baf7a", "#eb6834", "#e87ba4", "#7c3aed", "#171717"];
const ACCENT = ["#f59e0b", "#14b8a6", "#ef4444", "#8b5cf6", "#0ea5e9", "#84cc16"];

export default function ColorPickerDemo() {
  const [brand, setBrand] = React.useState("#2563eb");
  const [accent, setAccent] = React.useState("#f59e0b");
  const b = readable(brand);
  const a = readable(accent);

  return (
    <div className="flex min-h-screen w-full items-center justify-center bg-background p-6">
      <div className="grid w-full max-w-[780px] min-w-0 overflow-hidden rounded-[18px] [corner-shape:squircle] bg-card shadow-sm ring-1 ring-border sm:grid-cols-[300px_minmax(0,1fr)]">
        <div className="p-6">
          <h2 className="text-[17px] font-semibold tracking-[-0.01em]">Brand theme</h2>
          <p className="mt-1 text-[13px] text-muted-foreground">Used on signing pages and emails your clients see.</p>
          <div className="mt-6 grid gap-5">
            <Field label="Brand colour" hint={`Text on it: ${b.ink === "#ffffff" ? "white" : "black"} · ${b.ratio.toFixed(1)}:1`}>
              <ColorPicker value={brand} onValueChange={setBrand} swatches={BRAND} />
            </Field>
            <Field label="Accent colour" hint={`Text on it: ${a.ink === "#ffffff" ? "white" : "black"} · ${a.ratio.toFixed(1)}:1`}>
              <ColorPicker value={accent} onValueChange={setAccent} swatches={ACCENT} />
            </Field>
          </div>
          <p className="mt-6 flex items-center gap-1.5 text-[12px] text-muted-foreground" aria-live="polite">
            {Math.min(b.ratio, a.ratio) >= 4.5 ? (
              <><Check className="size-3.5" aria-hidden /> Both pass AA contrast</>
            ) : (
              <><AlertTriangle className="size-3.5" aria-hidden /> One colour is below AA (4.5:1)</>
            )}
          </p>
        </div>

        <div className="border-t border-border bg-muted/40 p-6 sm:border-t-0 sm:border-l" aria-label="Preview">
          <p className="mb-3 text-[11.5px] font-medium tracking-[0.06em] text-muted-foreground uppercase">Preview</p>
          <div className="overflow-hidden rounded-[14px] [corner-shape:squircle] bg-background shadow-sm ring-1 ring-border">
            <div className="flex items-center gap-2.5 px-4 py-3.5" style={{ background: brand, color: b.ink }}>
              <span className="grid size-7 place-items-center rounded-[8px] [corner-shape:squircle] text-[12px] font-bold" style={{ background: b.ink, color: brand }}>
                N
              </span>
              <span className="text-[13.5px] font-semibold">Northwind Studio</span>
              <span className="ml-auto rounded-full px-2 py-0.5 text-[11px] font-semibold" style={{ background: accent, color: a.ink }}>
                Action needed
              </span>
            </div>
            <div className="grid gap-4 p-4">
              <div className="flex items-start gap-3">
                <span className="grid size-9 shrink-0 place-items-center rounded-[10px] [corner-shape:squircle] bg-muted">
                  <FileSignature className="size-4" aria-hidden />
                </span>
                <div className="min-w-0">
                  <p className="text-[13.5px] font-medium">Master services agreement</p>
                  <p className="text-[12.5px] text-muted-foreground">Daniel, this is ready for your signature.</p>
                </div>
              </div>
              <div>
                <div className="flex justify-between text-[11.5px] text-muted-foreground">
                  <span>2 of 3 signers</span>
                  <span>Due 12 Oct</span>
                </div>
                <div className="mt-1.5 h-1.5 overflow-hidden rounded-full bg-muted">
                  <div className="h-full w-2/3 rounded-full" style={{ background: accent }} />
                </div>
              </div>
              <div className="flex items-center gap-3">
                <span className="inline-flex h-9 items-center rounded-[10px] [corner-shape:squircle] px-3.5 text-[13px] font-medium" style={{ background: brand, color: b.ink }}>
                  Review and sign
                </span>
                <span className="text-[13px] font-medium underline underline-offset-4" style={{ textDecorationColor: brand }}>
                  Download PDF
                </span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

Dependencies

More by Mohamed Uvaish

View all
  • Signature Pad

    Signature Pad

    420
  • Folder Card

    Folder Card

    336
  • Share Dialog

    Share Dialog

    308
  • Kanban Board

    Kanban Board

    249
  • Notification Panel

    Notification Panel

    102
  • Charts & KPI Cards

    Charts & KPI Cards

    86
  • Rich Text Editor

    Rich Text Editor

    44
  • Command Menu

    Command Menu

    34

More in Forms

View all
  • Premium Auth

    Premium Auth

    500
  • Login 1

    Login 1

    52
  • Book A Demo 3

    Book A Demo 3

    83
  • Authentication Card

    Authentication Card

    47
  • Contact Card

    Contact Card

    1K
  • Login Card

    Login Card

    32
  • Book A Demo 1

    Book A Demo 1

    69
  • Login 2

    Login 2

    7

Explore more

Part of Layro System — browse the full library on 21st.dev.