# Color Swatch (/ui/components/react/color-swatch)




## Usage [#usage]

```tsx
import { ColorSwatch } from '@appica/ui-react/color-swatch'
import { parseColor } from '@appica/ui-react/color'
```

```tsx
<ColorSwatch color="#3b82f6" />
```

`ColorSwatch` shows one color as a tile. It's the read-only member of the color family: [Color Area](/ui/components/react/color-area) and [Color Slider](/ui/components/react/color-slider) pick a color, and the swatch reports the one you landed on. All three take the same `Color` value, so a swatch drops into a picker with no conversion.

```tsx
const [color, setColor] = useState(() => parseColor('#3b82f6'))

<ColorSwatch color={color} />
```

`color` takes a `Color` or any CSS color string, so `'#3b82f6'`, `'rgba(59, 130, 246, 0.7)'` and a parsed object are all equivalent.

The swatch borrows the border and the disabled treatment from the other two controls, so a picker built out of the family reads as one control rather than three.

Inside a [Color Picker](/ui/components/react/color-picker), `color` is optional: a bare `<ColorSwatch />` previews whatever the picker currently holds.

## Examples [#examples]

### Opacity [#opacity]

A translucent color composited straight onto the page is indistinguishable from the lighter opaque color it resolves to. The swatch draws it over a checkerboard instead, the same backdrop a `channel="alpha"` slider uses, so the transparency is visible.

`checkerboard={false}` turns it off, which lets the swatch blend into whatever sits behind it instead. The row below is the default, the row under it the same colors without the backdrop.

```tsx
import { ColorSwatch } from '@appica/ui-react/color-swatch'

const steps = [1, 0.75, 0.5, 0.25, 0.1]

export default function ColorSwatchOpacity() {
  return (
    <div className="flex flex-col items-center gap-6">
      <div className="flex items-center gap-4">
        {steps.map((alpha) => (
          <ColorSwatch key={alpha} color={`rgba(59, 130, 246, ${alpha})`} />
        ))}
      </div>
      <div className="flex items-center gap-4">
        {steps.map((alpha) => (
          <ColorSwatch key={alpha} color={`rgba(59, 130, 246, ${alpha})`} checkerboard={false} />
        ))}
      </div>
    </div>
  )
}
```

### Shapes [#shapes]

`shape="rounded"` is the default. Its corner is a percentage of the swatch, so it stays proportional at every size instead of flattening out as the tile grows - the same trick [Avatar](/ui/components/react/avatar) and [Thumbnail](/ui/components/react/thumbnail) use. `shape="circle"` is the alternative, and pairs well with an inline mention of a color in running text.

```tsx
import { ColorSwatch } from '@appica/ui-react/color-swatch'

export default function ColorSwatchShapes() {
  return (
    <div className="flex items-center gap-4">
      <ColorSwatch color="#3b82f6" />
      <ColorSwatch color="#3b82f6" shape="circle" />
    </div>
  )
}
```

### Sizing [#sizing]

The swatch is 40px square by default. `size` runs `3xs` 16px through `xl` 64px: the same ladder [Avatar](/ui/components/react/avatar) and [Thumbnail](/ui/components/react/thumbnail) use, shifted one step down because a swatch is read beside a value rather than looked at. Every shared name keeps its pixel size, so `sm` is 32px on all three. A plain pixel number works too, and a `size-*` class on the root overrides both.

```tsx
import { ColorSwatch } from '@appica/ui-react/color-swatch'

const sizes = ['3xs', '2xs', 'xs', 'sm', 'md', 'lg', 'xl'] as const

export default function ColorSwatchSizes() {
  return (
    <div className="flex flex-col items-center gap-6">
      <div className="flex flex-wrap items-center justify-center gap-4">
        {sizes.map((size) => (
          <ColorSwatch key={size} color="#3b82f6" size={size} />
        ))}
      </div>
      <div className="flex items-center gap-4">
        <ColorSwatch color="#a855f7" size={56} />
        <ColorSwatch color="#a855f7" className="size-24" />
      </div>
    </div>
  )
}
```

### Building a picker [#building-a-picker]

An area for two channels, a hue slider for the third, an alpha slider, and a swatch for the result - the same four parts the [Color Area](/ui/components/react/color-area) and [Color Slider](/ui/components/react/color-slider) pages build. The swatch is the only one of them that shows the alpha as alpha.

```tsx
'use client'

import { useState } from 'react'
import { ColorArea } from '@appica/ui-react/color-area'
import { ColorSlider } from '@appica/ui-react/color-slider'
import { ColorSwatch } from '@appica/ui-react/color-swatch'
import { type Color, formatColor, parseColor } from '@appica/ui-react/color'

export default function ColorSwatchPicker() {
  const [color, setColor] = useState<Color>(() => parseColor('hsb(217, 76%, 96%)'))

  return (
    <div className="flex w-full max-w-56 flex-col gap-3">
      <ColorArea
        value={color}
        onValueChange={setColor}
        xChannel="saturation"
        yChannel="brightness"
        aria-label="Saturation and brightness"
      />
      <ColorSlider channel="hue" value={color} onValueChange={setColor} />
      <ColorSlider channel="alpha" value={color} onValueChange={setColor} />
      <div className="flex items-center gap-3">
        <ColorSwatch color={color} />
        <span className="font-mono text-xs text-nowrap">
          {color.alpha < 1 ? formatColor(color, 'rgba') : formatColor(color, 'hex')}
        </span>
      </div>
    </div>
  )
}
```

### Disabled [#disabled]

`disabled` swaps the color for a flat muted fill inside a dashed outline, dimmed. It's the same treatment the area and the slider use, for a color a palette can't offer right now.

```tsx
import { ColorSwatch } from '@appica/ui-react/color-swatch'

export default function ColorSwatchDisabled() {
  return (
    <div className="flex items-center gap-4">
      <ColorSwatch color="#3b82f6" disabled />
      <ColorSwatch color="#3b82f6" shape="circle" disabled />
    </div>
  )
}
```

## API reference [#api-reference]

| Prop           | Type                                   | Default     | Description                                                                                                                                                                               |
| -------------- | ----------------------------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `color`        | `Color \| string`                                                  | -           | Color to show. Pass a `Color` or any CSS color string. Inside a `ColorPicker` it can be left off, and the swatch previews whatever the picker currently holds.                                                                   |
| `colorName`    | `string`                                                                      | color's own | Name announced for the color, in place of the description built from the color itself. Use it for the name your palette gives the color, e.g. `'Fire truck red'`.                                                                |
| `shape`        | `'rounded' \| 'circle'`                                            | `'rounded'` | Rounded square or full circle.                                                                                                                                                                                                   |
| `size`         | `'3xs' \| '2xs' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| number` | `'md'`      | A preset scale, or a pixel number for an exact size.                                                                                                                                                                             |
| `checkerboard` | `boolean`                                                                     | `true`      | Back a translucent color with a checkerboard, so it reads as translucent rather than as the flat color it composites to. Turn it off to let the swatch blend into whatever sits behind it. An opaque color covers it either way. |
| `disabled`     | `boolean`                                                                     | `false`     | Dim the swatch and swap the color for a flat muted fill.                                                                                                                                                                         |
| `aria-label`   | `string`                                                                      | -           | Extra context, appended to the color's name rather than replacing it, e.g. `Background color`.                                                                                                                                   |
| `children`     | `ReactNode`                                                                   | -           | Content laid over the color, centered.                                                                                                                                                                                           |
| `className`    | `string`                                                                      | -           | Extra classes on the root, merged via `tailwind-merge`.                                                                                                                                                                          |

Every other `<span>` attribute is forwarded to the root. The root carries `data-disabled`; the parts are addressable through `data-slot` (`color-swatch`, `color-swatch-surface`).

The color model - `Color`, `parseColor`, `formatColor`, `convertColor` and the channel helpers - ships from `@appica/ui-react/color` and is documented on the [Color Area](/ui/components/react/color-area#api-reference) page.

## Accessibility [#accessibility]

* The swatch is a `role="img"` with a name, not a decorative div, so a color that carries meaning is reachable rather than invisible.
* That name is an English description built from the color - `vivid blue`, `dark muted green`, `light gray` - because a hex string is announced digit by digit and tells a listener nothing. Below full opacity it ends with the opacity, e.g. `vivid blue, 50% opacity`.
* `colorName` replaces that description with the name your palette uses. `aria-label` is appended to it rather than replacing it, so `colorName="Fire truck red"` with `aria-label="Background color"` announces `Fire truck red, Background color`.
* The hairline border is drawn as an overlay rather than as a border on the root, so it survives a pale color without changing the swatch's box.
* `forced-color-adjust: none` keeps the color and the checkerboard intact in forced-colors mode, where the whole point of the component would otherwise be overridden.
* A swatch is not a control. When it needs to be clickable, wrap it in a `<button>`: that gives you the focus ring, the pressed state and the keyboard handling for free, and keeps the swatch itself presentational.
