10.1k

Swatch

PreviousNext

Color and image swatch toggle component for product variant selection.

<script setup lang="ts">
import { Swatch } from '@/components/ui/swatch'
</script>

<template>
  <div class="flex flex-wrap items-start gap-4">
    <Swatch hex="#ef4444" label="Red" />
    <Swatch hex="#3b82f6" label="Blue" />
    <Swatch hex="#22c55e" label="Green" />
    <Swatch hex="#f59e0b" label="Amber" />
  </div>
</template>

Installation

pnpm dlx @frontic/ui add swatch

Usage

<script setup lang="ts">
import { Swatch } from '@/components/ui/swatch'
</script>

<template>
  <Swatch hex="#3b82f6" />
</template>

With Image

Use SwatchImage inside a Swatch to display an image with automatic load-state handling.

<script setup lang="ts">
import { Swatch, SwatchImage } from '@/components/ui/swatch'
</script>

<template>
  <Swatch>
    <SwatchImage src="/images/pattern.jpg" alt="Pattern" />
  </Swatch>
</template>

With Fallback

Use SwatchImage and SwatchFallback for image swatches with automatic load-state handling. When the image loads, the fallback hides. When it fails, the fallback shows.

<script setup lang="ts">
import { Swatch, SwatchFallback, SwatchImage } from '@/components/ui/swatch'
</script>

<template>
  <div class="flex flex-wrap items-center gap-4">
    <Swatch hex="#ef4444">
      <SwatchImage src="https://images.unsplash.com/photo-1558171813-4c088753af8f?w=100&h=100&fit=crop" alt="Red pattern" />
      <SwatchFallback class="flex items-center justify-center text-[10px] text-white">Red</SwatchFallback>
    </Swatch>

    <Swatch hex="#3b82f6">
      <SwatchImage src="/invalid-image.jpg" alt="Broken image" />
      <SwatchFallback class="flex items-center justify-center text-[10px] text-white">Blue</SwatchFallback>
    </Swatch>

    <Swatch>
      <SwatchImage src="/invalid-image.jpg" alt="Broken image" />
      <SwatchFallback class="flex items-center justify-center bg-violet-400 text-[10px] text-white">Violet</SwatchFallback>
    </Swatch>
  </div>
</template>
<script setup lang="ts">
import { Swatch, SwatchFallback, SwatchImage } from '@/components/ui/swatch'
</script>

<template>
  <Swatch hex="#ef4444">
    <SwatchImage src="/images/pattern.jpg" alt="Red pattern" />
    <SwatchFallback>Red</SwatchFallback>
  </Swatch>
</template>

Sizes

<script setup lang="ts">
import { Swatch } from '@/components/ui/swatch'
</script>

<template>
  <div class="flex flex-wrap items-center gap-4">
    <Swatch size="sm" hex="#3b82f6" />
    <Swatch size="md" hex="#3b82f6" />
    <Swatch size="lg" hex="#3b82f6" />
  </div>
</template>

Pill

Use the pill prop to make the swatch fully rounded. Combines with any size.

<script setup lang="ts">
import { Swatch } from '@/components/ui/swatch'
</script>

<template>
  <div class="flex flex-wrap items-center gap-4">
    <Swatch pill hex="#ef4444" />
    <Swatch pill hex="#3b82f6" />
    <Swatch pill hex="#22c55e" />
    <Swatch pill hex="#f59e0b" />
  </div>
</template>

Examples

Color Swatches

<script setup lang="ts">
import { ref } from 'vue'
import { Swatch } from '@/components/ui/swatch'

const colors = ['#ef4444', '#f97316', '#f59e0b', '#22c55e', '#3b82f6', '#8b5cf6', '#ec4899']
const selected = ref('#3b82f6')
</script>

<template>
  <div class="flex flex-wrap items-center gap-2">
    <Swatch
      v-for="color in colors"
      :key="color"
      :hex="color"
      :pressed="selected === color"
      @update:pressed="selected = color"
    />
  </div>
</template>

Image Swatches

<script setup lang="ts">
import { ref } from 'vue'
import { Swatch, SwatchImage } from '@/components/ui/swatch'

const images = [
  'https://images.unsplash.com/photo-1558171813-4c088753af8f?w=100&h=100&fit=crop',
  'https://images.unsplash.com/photo-1557682250-33bd709cbe85?w=100&h=100&fit=crop',
  'https://images.unsplash.com/photo-1557682224-5b8590cd9ec5?w=100&h=100&fit=crop',
  'https://images.unsplash.com/photo-1557682260-96773eb01377?w=100&h=100&fit=crop',
]
const selected = ref(images[0])
</script>

<template>
  <div class="flex flex-wrap items-center gap-2">
    <Swatch
      v-for="image in images"
      :key="image"
      :pressed="selected === image"
      @update:pressed="selected = image"
    >
      <SwatchImage :src="image" alt="Pattern" />
    </Swatch>
  </div>
</template>

Controlled Selection

Use v-model:pressed to control the toggle state for selection UI.

Selected: #3b82f6

<script setup lang="ts">
import { ref } from 'vue'
import { Swatch } from '@/components/ui/swatch'

const colors = ['#ef4444', '#3b82f6', '#22c55e']
const selectedColor = ref<string | null>('#3b82f6')

function selectColor(color: string) {
  selectedColor.value = selectedColor.value === color ? null : color
}
</script>

<template>
  <div class="flex flex-col gap-4">
    <div class="flex flex-wrap items-center gap-2">
      <Swatch
        v-for="color in colors"
        :key="color"
        :hex="color"
        :pressed="selectedColor === color"
        @update:pressed="selectColor(color)"
      />
    </div>
    <p class="text-sm text-muted-foreground">
      Selected: {{ selectedColor ?? 'None' }}
    </p>
  </div>
</template>

API Reference

Swatch

Renders a toggle button. Use hex for color swatches or compose with SwatchImage for pattern/texture swatches.

PropTypeDefaultDescription
hexstringCSS color value to display
labelstringLabel text below the swatch
labelClassstringCSS classes for the label
size'sm' | 'md' | 'lg''md'Swatch size
pillbooleanfalseUse rounded pill shape
pressedbooleanfalseToggle state
disabledbooleanfalseDisable the swatch
<script setup lang="ts">
import { Swatch } from '@/components/ui/swatch'
</script>

<template>
  <Swatch hex="#3b82f6" pill size="lg" label="Blue" />
</template>

SwatchLabel

Renders a label for a swatch. Used internally when the label prop is set, or use directly via the #label slot for custom styling.

PropTypeDefaultDescription
classstringAdditional CSS classes

SwatchImage

Renders an image inside a swatch with automatic load-state tracking. Must be used inside Swatch or SwatchGroupItem. Shows only when the image has loaded successfully.

PropTypeDefaultDescription
srcstringrequiredImage URL
altstringAlt text for the image
referrerPolicystringReferrer policy for the image
crossOriginstringCross-origin setting for the image
asChildbooleanfalseRender as child element
EventPayloadDescription
loadingStatusChange'idle' | 'loading' | 'loaded' | 'error'Emitted when image loading status changes

SwatchFallback

Renders fallback content when SwatchImage fails to load or is not provided. Must be used inside Swatch or SwatchGroupItem.

PropTypeDefaultDescription
delayMsnumberDelay before showing fallback (ms)
asChildbooleanfalseRender as child element