Skip to content

ColorSwatch

A color preview element that displays a color with a checkerboard background for visualizing alpha transparency.

Preview

Source code
tsx
import { useState } from "react";
import { Color } from "@urcolor/core";
import { ColorSwatch } from "@urcolor/react";

const colors = [
  Color.parse("hsl(210, 80%, 50%)")!,
  Color.parse("hsl(350, 90%, 60%)")!,
  Color.parse("hsl(120, 60%, 45%)")!,
  Color.parse("hsla(45, 100%, 55%, 0.5)")!,
];

export default function ColorSwatchBasic() {
  const [selected, setSelected] = useState(0);

  return (
    <div className="flex items-center gap-3">
      {colors.map((color, i) => (
        <ColorSwatch
          key={i}
          value={color}
          alpha
          className="flex size-10 cursor-pointer items-center justify-center rounded-lg"
          onClick={() => setSelected(i)}
        >
          <svg
            className={`size-5 text-white drop-shadow-[0_1px_2px_rgba(0,0,0,0.5)] transition-opacity duration-150 ${selected === i ? "opacity-100" : "opacity-0"}`}
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            strokeWidth={2}
            strokeLinecap="round"
            strokeLinejoin="round"
          >
            <polyline points="20 6 9 17 4 12" />
          </svg>
        </ColorSwatch>
      ))}
    </div>
  );
}

Anatomy

ColorSwatch is the whole family, a single component with no sub-parts, imported directly from @urcolor/react. There is no ColorSwatch.* namespace and no ColorSwatch.Root.

tsx
import { ColorSwatch } from "@urcolor/react";

<ColorSwatch value="hsl(210, 80%, 50%)" />

Examples

Basic

A set of color swatches, including one with alpha transparency.

Source code
tsx
import { useState } from "react";
import { Color } from "@urcolor/core";
import { ColorSwatch } from "@urcolor/react";

const colors = [
  Color.parse("hsl(210, 80%, 50%)")!,
  Color.parse("hsl(350, 90%, 60%)")!,
  Color.parse("hsl(120, 60%, 45%)")!,
  Color.parse("hsla(45, 100%, 55%, 0.5)")!,
];

export default function ColorSwatchBasic() {
  const [selected, setSelected] = useState(0);

  return (
    <div className="flex items-center gap-3">
      {colors.map((color, i) => (
        <ColorSwatch
          key={i}
          value={color}
          alpha
          className="flex size-10 cursor-pointer items-center justify-center rounded-lg"
          onClick={() => setSelected(i)}
        >
          <svg
            className={`size-5 text-white drop-shadow-[0_1px_2px_rgba(0,0,0,0.5)] transition-opacity duration-150 ${selected === i ? "opacity-100" : "opacity-0"}`}
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 24 24"
            fill="none"
            stroke="currentColor"
            strokeWidth={2}
            strokeLinecap="round"
            strokeLinejoin="round"
          >
            <polyline points="20 6 9 17 4 12" />
          </svg>
        </ColorSwatch>
      ))}
    </div>
  );
}

API Reference

ColorSwatch

Renders a color preview with an automatic checkerboard background. Standalone it renders a <div role="img">; inside a ColorSwatchGroup it renders a toggle <button> instead, and its value doubles as the group's selection key.

Extends Omit<ComponentPropsWithoutRef<"div">, "value">.

PropTypeDefaultDescription
valueColor | string | nullThe color value to display. Inside a ColorSwatchGroup it is also the toggle selection key.
checkerSizenumber16The checkerboard tile size in pixels.
alphabooleanfalseWhen true, reflects the color's alpha channel. When false, displays the color as fully opaque.
disabledbooleanfalsePrevents interaction with this swatch. Only meaningful inside a group; a standalone swatch is not interactive.
asReact.ElementType'div'The element or component to render as. Ignored inside a group, where a <button> is always rendered.
classNamestringClass applied to the rendered element.
styleReact.CSSPropertiesInline styles merged over the generated background and custom properties.
childrenReact.ReactNodeRendered inside the swatch, e.g. a selection checkmark.

TIP

A swatch inside a group is disabled when either its own disabled prop or the group's disabled prop is set.

Data Attributes

These are emitted only when the swatch sits inside a ColorSwatchGroup. A standalone swatch carries neither.

AttributePresent when
data-stateAlways, as "on" when the swatch is selected and "off" when it is not.
data-disabledThe swatch or its group is disabled.

CSS Variables

The component exposes CSS custom properties on the rendered element for advanced styling:

VariableDescription
--urcolor-swatch-colorThe painted color, honouring alpha. transparent when there is no color.
--urcolor-swatch-color-opaqueThe same color forced to alpha 1.
--urcolor-swatch-alphaThe color's alpha channel, 1 when there is no color.
--urcolor-swatch-checkerboardThe transparency grid painted under the color.
--urcolor-swatch-backgroundThe composited background, built from the four above.

All five are always emitted, including when the value is absent or unparseable, so your styling never has to guard for a missing variable. The unprefixed --swatch-color, --swatch-color-opaque, --swatch-alpha and --swatch-checkerboard are still emitted as aliases of their replacements and are deprecated.

The grid itself reads three further properties, and no component writes them, so a rule anywhere above the element wins:

VariableDefaultDescription
--urcolor-checkerboard-darkrgb(230, 230, 230)The darker of the two checks.
--urcolor-checkerboard-lightwhiteThe lighter of the two checks.
--urcolor-checkerboard-size16pxThe tile size. checkerSize writes it inline, which beats a stylesheet.

Accessibility

A standalone ColorSwatch is a purely visual element: it carries role="img" but is not focusable and handles no keyboard input. Inside a ColorSwatchGroup the same component becomes a toggle button and joins the group's roving tab stop.

ARIA Labels

AttributeDescription
role="img"Always applied, identifying the swatch as an image for screen readers.
aria-pressedApplied inside a group, reflecting the selection state.
aria-labelNot generated. role="img" requires an accessible name, so pass your own aria-label describing the color.

Provide an accessible name

The React swatch does not derive a label from the color. An element with role="img" and no accessible name is a WCAG failure, so supply aria-label, for example aria-label="Blue" or the CSS color string.

Keyboard Navigation

A standalone swatch is not focusable. The keys below apply only inside a ColorSwatchGroup.

KeyAction
TabMove focus into the group, landing on the item that owns the tab stop
Arrow Right / Arrow LeftMove between swatches in a horizontal group
Arrow Down / Arrow UpMove between swatches in a vertical group
Home / EndMove to the first / last swatch
Enter or SpaceToggle the focused swatch's selection