Color Swatch
A color swatch component for displaying color values with support for transparency and various sizes.
import { ColorSwatch } from "@/components/ui/color-swatch";
export function ColorSwatchDemo() {
return (
<div className="flex flex-col gap-6">
<div className="flex items-center gap-3">
<ColorSwatch color="#3b82f6" />
<span className="font-medium text-sm">Primary Blue</span>
</div>
<div className="flex items-center gap-3">
<ColorSwatch color="#ef4444" size="sm" />
<ColorSwatch color="#ef4444" size="default" />
<ColorSwatch color="#ef4444" size="lg" />
<span className="font-medium text-sm">Different Sizes</span>
</div>
<div className="flex items-center gap-3">
<ColorSwatch color="rgba(59, 130, 246, 0.5)" />
<span className="font-medium text-sm">Semi-transparent Blue</span>
</div>
<div className="flex items-center gap-3">
<span className="font-medium text-sm">Color Palette</span>
<div className="flex gap-2">
<ColorSwatch color="#ef4444" />
<ColorSwatch color="#f97316" />
<ColorSwatch color="#eab308" />
<ColorSwatch color="#22c55e" />
<ColorSwatch color="#3b82f6" />
<ColorSwatch color="#8b5cf6" />
<ColorSwatch color="#ec4899" />
</div>
</div>
<div className="flex items-center gap-3">
<ColorSwatch color="#ef4444" disabled />
<span className="font-medium text-sm">Disabled</span>
</div>
</div>
);
}
Installation
CLI
npx shadcn@latest add "https://diceui.com/r/color-swatch"
pnpm dlx shadcn@latest add "https://diceui.com/r/color-swatch"
yarn dlx shadcn@latest add "https://diceui.com/r/color-swatch"
bun x shadcn@latest add "https://diceui.com/r/color-swatch"
Manual
Install the following dependencies:
npm install @radix-ui/react-slot class-variance-authority
pnpm add @radix-ui/react-slot class-variance-authority
yarn add @radix-ui/react-slot class-variance-authority
bun add @radix-ui/react-slot class-variance-authority
Copy and paste the following code into your project.
"use client";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react";
import { cn } from "@/lib/utils";
const colorSwatchVariants = cva(
"box-border rounded-sm border shadow-sm [background-clip:padding-box] data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
{
variants: {
size: {
default: "size-8",
sm: "size-6",
lg: "size-12",
},
},
defaultVariants: {
size: "default",
},
},
);
function getIsCssColor(v: string): boolean {
try {
return typeof CSS !== "undefined" && typeof CSS.supports === "function"
? CSS.supports("color", v)
: true;
} catch {
return false;
}
}
function getHasAlpha(v: string): boolean {
const s = v.trim().toLowerCase();
if (s === "transparent") return true;
if (/^#(?:[0-9a-f]{4}|[0-9a-f]{8})$/i.test(s)) return true;
if (/\b(?:rgba|hsla)\s*\(/i.test(s)) return true;
if (
/\b(?:rgb|hsl|lab|lch|oklab|oklch|color)\s*\([^)]*\/\s*[\d.]+%?\s*\)/i.test(
s,
)
) {
return true;
}
return false;
}
interface ColorSwatchProps
extends Omit<React.ComponentProps<"div">, "children">,
VariantProps<typeof colorSwatchVariants> {
color?: string;
asChild?: boolean;
disabled?: boolean;
withoutTransparency?: boolean;
}
function ColorSwatch({
color,
size = "default",
asChild = false,
disabled = false,
withoutTransparency = false,
className,
style,
...props
}: ColorSwatchProps) {
const colorValue = color?.trim();
const backgroundStyle = React.useMemo<React.CSSProperties>(() => {
if (!colorValue) {
return {
background:
"linear-gradient(to bottom right, transparent calc(50% - 1px), hsl(var(--destructive)) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) no-repeat",
};
}
if (!getIsCssColor(colorValue)) {
return { backgroundColor: "transparent" };
}
if (!withoutTransparency && getHasAlpha(colorValue)) {
return {
background: `linear-gradient(${colorValue}, ${colorValue}), repeating-conic-gradient(#ccc 0% 25%, #fff 0% 50%) 0% 50% / 10px 10px`,
};
}
return { backgroundColor: colorValue };
}, [colorValue, withoutTransparency]);
const ariaLabel = !colorValue
? "No color selected"
: `Color swatch: ${colorValue}`;
const Primitive = asChild ? Slot : "div";
return (
<Primitive
role="img"
aria-label={ariaLabel}
aria-disabled={disabled || undefined}
data-slot="color-swatch"
data-disabled={disabled ? "" : undefined}
{...props}
className={cn(colorSwatchVariants({ size }), className)}
style={{
...backgroundStyle,
forcedColorAdjust: "none",
...style,
}}
/>
);
}
export { ColorSwatch };
Usage
Import the component and use it to display color values.
import { ColorSwatch } from "@/components/ui/color-swatch";
<ColorSwatch value="#3b82f6" />
Examples
Different Sizes
The color swatch component supports three different sizes: sm
, default
, and lg
.
import { ColorSwatch } from "@/components/ui/color-swatch";
const colors = [
"#ef4444", // red
"#f97316", // orange
"#eab308", // yellow
"#22c55e", // green
"#3b82f6", // blue
];
export function ColorSwatchSizesDemo() {
return (
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-2">
<span className="font-medium text-sm">Small (sm)</span>
<div className="flex gap-2">
{colors.map((color, index) => (
<ColorSwatch key={index} color={color} size="sm" />
))}
</div>
</div>
<div className="flex flex-col gap-2">
<span className="font-medium text-sm">Default</span>
<div className="flex gap-2">
{colors.map((color, index) => (
<ColorSwatch key={index} color={color} size="default" />
))}
</div>
</div>
<div className="flex flex-col gap-2">
<span className="font-medium text-sm">Large (lg)</span>
<div className="flex gap-2">
{colors.map((color, index) => (
<ColorSwatch key={index} color={color} size="lg" />
))}
</div>
</div>
</div>
);
}
Transparency Support
The color swatch automatically detects transparent colors and displays them with a checkerboard background pattern.
import { ColorSwatch } from "@/components/ui/color-swatch";
export function ColorSwatchTransparencyDemo() {
return (
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-2">
<span className="font-medium text-sm">Alpha Transparency</span>
<div className="flex gap-2">
<ColorSwatch color="rgba(59, 130, 246, 1)" />
<ColorSwatch color="rgba(59, 130, 246, 0.8)" />
<ColorSwatch color="rgba(59, 130, 246, 0.6)" />
<ColorSwatch color="rgba(59, 130, 246, 0.4)" />
<ColorSwatch color="rgba(59, 130, 246, 0.2)" />
</div>
</div>
<div className="flex flex-col gap-2">
<span className="font-medium text-sm">HSLA Colors</span>
<div className="flex gap-2">
<ColorSwatch color="hsla(220, 91%, 60%, 1)" />
<ColorSwatch color="hsla(220, 91%, 60%, 0.75)" />
<ColorSwatch color="hsla(220, 91%, 60%, 0.5)" />
<ColorSwatch color="hsla(220, 91%, 60%, 0.25)" />
<ColorSwatch color="hsla(220, 91%, 60%, 0.1)" />
</div>
</div>
<div className="flex flex-col gap-2">
<span className="font-medium text-sm">
Without Transparency Pattern
</span>
<div className="flex gap-2">
<ColorSwatch color="rgba(239, 68, 68, 0.8)" withoutTransparency />
<ColorSwatch color="rgba(34, 197, 94, 0.6)" withoutTransparency />
<ColorSwatch color="rgba(139, 92, 246, 0.4)" withoutTransparency />
</div>
</div>
<div className="flex flex-col gap-2">
<span className="font-medium text-sm">
With Transparency Pattern (Default)
</span>
<div className="flex gap-2">
<ColorSwatch color="rgba(239, 68, 68, 0.8)" />
<ColorSwatch color="rgba(34, 197, 94, 0.6)" />
<ColorSwatch color="rgba(139, 92, 246, 0.4)" />
</div>
</div>
</div>
);
}
API Reference
ColorSwatch
A color swatch component that displays a color value with optional transparency support.
Prop | Type | Default |
---|---|---|
asChild? | boolean | false |
disabled? | boolean | false |
withoutTransparency? | boolean | false |
size? | "default" | "sm" | "lg" | "default" |
color? | string | undefined |
Data Attribute | Value |
---|---|
[data-disabled] | Present when the component is disabled. |
[data-slot] | Always set to 'color-swatch' for identification. |
Accessibility
The color swatch component includes proper accessibility features:
- ARIA Label: Automatically generates descriptive
aria-label
text based on the color value - Role: Uses
role="img"
to indicate it's an image representation of a color - Disabled State: Properly handles disabled state with appropriate visual and interaction changes
Screen Reader Support
- When a color value is provided, the
aria-label
reads "Color swatch: [color-value]" - When no color is selected, the
aria-label
reads "No color selected"
Color Format Support
The color swatch component supports various color formats:
- HEX:
#3b82f6
- RGB:
rgb(59, 130, 246)
- RGBA:
rgba(59, 130, 246, 0.5)
- HSL:
hsl(217, 91%, 60%)
- HSLA:
hsla(217, 91%, 60%, 0.5)
- Named Colors:
blue
,red
, etc.
Transparency Detection
The component automatically detects transparent colors by checking for:
rgba()
orhsla()
function notation- RGB/HSL with 4 values (including alpha)
- Any color format that includes transparency information
When transparency is detected, a checkerboard pattern is displayed behind the color to show the transparency effect. Use the withoutTransparency
prop to disable this behavior.
Usage with Forms
The color swatch component can be used as a form control by utilizing the asChild
prop:
<ColorSwatch asChild>
<button type="button" onClick={handleColorSelect}>
<span className="sr-only">Select color</span>
</button>
</ColorSwatch>
Styling
The component uses CSS custom properties for styling:
- Uses
forcedColorAdjust: none
to maintain color accuracy in high contrast mode - Supports all standard HTML div attributes and styling
- Can be customized with additional CSS classes via the
className
prop