Skip to content

ColorRing

A circular ring component for adjusting a single color channel along a circular arc.

Preview

#1980e6
Source code
vue
<script setup lang="ts">
import "internationalized-color/css";
import {
  ColorRingRoot,
  ColorRingTrack,
  ColorRingGradient,
  ColorRingThumb,
  useColor,
} from "@urcolor/vue";

const { color, hex } = useColor("hsl(210, 80%, 50%)");
</script>

<template>
  <code>{{ hex }}</code>
  <ColorRingRoot
    v-model="color"
    color-space="hsl"
    channel="h"
    :inner-radius="0.85"
    class="relative block size-64"
    style="container-type: inline-size"
  >
    <ColorRingTrack class="relative block size-full">
      <ColorRingGradient class="absolute inset-0 block" />
      <ColorRingThumb
        class="
          size-4 rounded-full border-2 border-white
          shadow-[0_0_0_1px_rgba(0,0,0,0.3),0_2px_4px_rgba(0,0,0,0.3)]
          focus-visible:shadow-[0_0_0_1px_rgba(0,0,0,0.3),0_0_0_3px_rgba(66,153,225,0.6)]
        "
      />
    </ColorRingTrack>
  </ColorRingRoot>
</template>

Anatomy

vue
<template>
  <ColorRingRoot>
    <ColorRingTrack>
      <ColorRingCheckerboard />
      <ColorRingGradient />
      <ColorRingThumb />
    </ColorRingTrack>
  </ColorRingRoot>
</template>

Examples

Hue

Hue ring slider for cycling through the color spectrum.

#1980e6
Source code
vue
<script setup lang="ts">
import "internationalized-color/css";
import {
  ColorRingRoot,
  ColorRingTrack,
  ColorRingGradient,
  ColorRingThumb,
  useColor,
} from "@urcolor/vue";

const { color, hex } = useColor("hsl(210, 80%, 50%)");
</script>

<template>
  <code>{{ hex }}</code>
  <ColorRingRoot
    v-model="color"
    color-space="hsl"
    channel="h"
    :inner-radius="0.85"
    class="relative block size-64"
    style="container-type: inline-size"
  >
    <ColorRingTrack class="relative block size-full">
      <ColorRingGradient class="absolute inset-0 block" />
      <ColorRingThumb
        class="
          size-4 rounded-full border-2 border-white
          shadow-[0_0_0_1px_rgba(0,0,0,0.3),0_2px_4px_rgba(0,0,0,0.3)]
          focus-visible:shadow-[0_0_0_1px_rgba(0,0,0,0.3),0_0_0_3px_rgba(66,153,225,0.6)]
        "
      />
    </ColorRingTrack>
  </ColorRingRoot>
</template>

Saturation

Saturation ring slider for adjusting color intensity.

#1980e6
Source code
vue
<script setup lang="ts">
import "internationalized-color/css";
import {
  ColorRingRoot,
  ColorRingTrack,
  ColorRingGradient,
  ColorRingThumb,
  useColor,
} from "@urcolor/vue";

const { color, hex } = useColor("hsl(210, 80%, 50%)");
</script>

<template>
  <code>{{ hex }}</code>
  <ColorRingRoot
    v-model="color"
    color-space="hsl"
    channel="s"
    :inner-radius="0.85"
    class="relative block size-64"
    style="container-type: inline-size"
  >
    <ColorRingTrack class="relative block size-full">
      <ColorRingGradient class="absolute inset-0 block" />
      <ColorRingThumb
        class="
          size-4 rounded-full border-2 border-white
          shadow-[0_0_0_1px_rgba(0,0,0,0.3),0_2px_4px_rgba(0,0,0,0.3)]
          focus-visible:shadow-[0_0_0_1px_rgba(0,0,0,0.3),0_0_0_3px_rgba(66,153,225,0.6)]
        "
      />
    </ColorRingTrack>
  </ColorRingRoot>
</template>

With Alpha

Pass :channel-overrides="false" on ColorRingGradient to reflect the color's alpha channel as opacity on the gradient. Add ColorRingCheckerboard behind the gradient to visualize transparency.

vue
<template>
  <ColorRingRoot
    :model-value="color"
    color-space="hsl"
    channel="h"
    @update:model-value="onColorUpdate"
  >
    <ColorRingTrack>
      <ColorRingCheckerboard />
      <ColorRingGradient :channel-overrides="false" />
      <ColorRingThumb />
    </ColorRingTrack>
  </ColorRingRoot>
</template>

API Reference

ColorRingRoot

The root container that manages ring state and color channel binding.

PropTypeDefaultDescription
modelValueColor | string | nullControlled color value (v-model).
defaultValueColor | string'hsl(0, 100%, 50%)'Initial color when uncontrolled.
colorSpacestring'hsl'Color space mode (e.g. 'hsl', 'oklch').
channelstringAutoChannel to control (e.g. 'h', 's'). Auto-derived from color space.
startAnglenumber0Starting angle offset in degrees.
innerRadiusnumber0.7Inner radius ratio (0–1) controlling ring thickness.
disabledbooleanfalseDisables interaction.
dir'ltr' | 'rtl'Reading direction.
namestringHidden input name for form submission.
requiredbooleanfalseMarks as required for form submission.
EventPayloadDescription
update:modelValueColor | undefinedEmitted when color changes.
valueCommitColorEmitted when interaction ends.

ColorRingTrack

The track container that holds the gradient, checkerboard, and thumb.

ColorRingGradient

Renders a ring gradient canvas for the track. Automatically samples the gradient from the root's color space and channel configuration.

PropTypeDefaultDescription
channelOverridesRecord<string, number> | false{ alpha: 1 }Lock specific channels to fixed values in the gradient. Set to false to reflect all channels from current color including alpha.

ColorRingCheckerboard

Renders a checkerboard pattern behind the gradient to visualize alpha transparency. Place it inside ColorRingTrack before ColorRingGradient.

ColorRingThumb

The draggable thumb element positioned along the ring arc.

Accessibility

ColorRing provides a circular slider interface for adjusting a single color channel with full keyboard support.

ARIA Labels

AttributeDescription
aria-labelLabels the slider with the controlled channel name.
role="slider"Applied to the thumb element for screen reader recognition.
aria-valuemin / aria-valuemaxDefines the channel's value range.
aria-valuenowCurrent value of the channel.

Keyboard Navigation

KeyAction
Arrow Right / Arrow UpIncrease by one step
Arrow Left / Arrow DownDecrease by one step
Shift + ArrowMove by 10 steps
Page UpIncrease by 10 steps
Page DownDecrease by 10 steps
HomeMove to minimum
EndMove to maximum