Color Picker
A component that allows users to select a color from a predefined set.
Usage
Saved Colors
'use client'
import { PipetteIcon } from 'lucide-react'
import { HStack, Stack } from 'styled-system/jsx'
import { ColorPicker, IconButton, Input, Text } from '~/components/ui'
export const Demo = (props: ColorPicker.RootProps) => {
  return (
    <ColorPicker.Root {...props}>
      <ColorPicker.Context>
        {(api) => (
          <>
            <ColorPicker.Label>Color Picker</ColorPicker.Label>
            <ColorPicker.Control>
              <ColorPicker.ChannelInput channel="hex" asChild>
                <Input />
              </ColorPicker.ChannelInput>
              <ColorPicker.Trigger asChild>
                <IconButton variant="outline">
                  <ColorPicker.Swatch value={api.value} />
                </IconButton>
              </ColorPicker.Trigger>
            </ColorPicker.Control>
            <ColorPicker.Positioner>
              <ColorPicker.Content>
                <Stack gap="3">
                  <ColorPicker.Area>
                    <ColorPicker.AreaBackground />
                    <ColorPicker.AreaThumb />
                  </ColorPicker.Area>
                  <HStack gap="3">
                    <ColorPicker.EyeDropperTrigger asChild>
                      <IconButton size="xs" variant="outline" aria-label="Pick a color">
                        <PipetteIcon />
                      </IconButton>
                    </ColorPicker.EyeDropperTrigger>
                    <Stack gap="2" flex="1">
                      <ColorPicker.ChannelSlider channel="hue">
                        <ColorPicker.ChannelSliderTrack />
                        <ColorPicker.ChannelSliderThumb />
                      </ColorPicker.ChannelSlider>
                      <ColorPicker.ChannelSlider channel="alpha">
                        <ColorPicker.TransparencyGrid size="8px" />
                        <ColorPicker.ChannelSliderTrack />
                        <ColorPicker.ChannelSliderThumb />
                      </ColorPicker.ChannelSlider>
                    </Stack>
                  </HStack>
                  <HStack>
                    <ColorPicker.ChannelInput channel="hex" asChild>
                      <Input size="2xs" />
                    </ColorPicker.ChannelInput>
                    <ColorPicker.ChannelInput channel="alpha" asChild>
                      <Input size="2xs" />
                    </ColorPicker.ChannelInput>
                  </HStack>
                  <Stack gap="1.5">
                    <Text size="xs" fontWeight="medium" color="fg.default">
                      Saved Colors
                    </Text>
                    <ColorPicker.SwatchGroup>
                      {presets.map((color, id) => (
                        <ColorPicker.SwatchTrigger key={id} value={color}>
                          <ColorPicker.Swatch value={color} />
                        </ColorPicker.SwatchTrigger>
                      ))}
                    </ColorPicker.SwatchGroup>
                  </Stack>
                </Stack>
              </ColorPicker.Content>
            </ColorPicker.Positioner>
          </>
        )}
      </ColorPicker.Context>
      <ColorPicker.HiddenInput />
    </ColorPicker.Root>
  )
}
const presets = [
  'hsl(10, 81%, 59%)',
  'hsl(60, 81%, 59%)',
  'hsl(100, 81%, 59%)',
  'hsl(175, 81%, 59%)',
  'hsl(190, 81%, 59%)',
  'hsl(205, 81%, 59%)',
  'hsl(220, 81%, 59%)',
  'hsl(250, 81%, 59%)',
  'hsl(280, 81%, 59%)',
  'hsl(350, 81%, 59%)',
]
Installation
npx @park-ui/cli components add color-picker1
Styled Primitive
Copy the code snippet below into ~/components/ui/primitives/color-picker.tsx
'use client'
import type { Assign } from '@ark-ui/react'
import { ColorPicker } from '@ark-ui/react/color-picker'
import { type ColorPickerVariantProps, colorPicker } from 'styled-system/recipes'
import type { ComponentProps, HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from '~/lib/create-style-context'
const { withProvider, withContext } = createStyleContext(colorPicker)
export type RootProviderProps = ComponentProps<typeof RootProvider>
export const RootProvider = withProvider<
  HTMLDivElement,
  Assign<Assign<HTMLStyledProps<'div'>, ColorPicker.RootProviderBaseProps>, ColorPickerVariantProps>
>(ColorPicker.RootProvider, 'root')
export type RootProps = ComponentProps<typeof Root>
export const Root = withProvider<
  HTMLDivElement,
  Assign<Assign<HTMLStyledProps<'div'>, ColorPicker.RootBaseProps>, ColorPickerVariantProps>
>(ColorPicker.Root, 'root')
export const AreaBackground = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.AreaBackgroundBaseProps>
>(ColorPicker.AreaBackground, 'areaBackground')
export const Area = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.AreaBaseProps>
>(ColorPicker.Area, 'area')
export const AreaThumb = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.AreaThumbBaseProps>
>(ColorPicker.AreaThumb, 'areaThumb')
export const ChannelInput = withContext<
  HTMLInputElement,
  Assign<HTMLStyledProps<'input'>, ColorPicker.ChannelInputBaseProps>
>(ColorPicker.ChannelInput, 'channelInput')
export const ChannelSliderLabel = withContext<
  HTMLLabelElement,
  Assign<HTMLStyledProps<'label'>, ColorPicker.ChannelSliderLabelBaseProps>
>(ColorPicker.ChannelSliderLabel, 'channelSliderLabel')
export const ChannelSlider = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.ChannelSliderBaseProps>
>(ColorPicker.ChannelSlider, 'channelSlider')
export const ChannelSliderThumb = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.ChannelSliderThumbBaseProps>
>(ColorPicker.ChannelSliderThumb, 'channelSliderThumb')
export const ChannelSliderTrack = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.ChannelSliderTrackBaseProps>
>(ColorPicker.ChannelSliderTrack, 'channelSliderTrack')
export const ChannelSliderValueText = withContext<
  HTMLSpanElement,
  Assign<HTMLStyledProps<'span'>, ColorPicker.ChannelSliderValueTextBaseProps>
>(ColorPicker.ChannelSliderValueText, 'channelSliderValueText')
export const Content = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.ContentBaseProps>
>(ColorPicker.Content, 'content')
export const Control = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.ControlBaseProps>
>(ColorPicker.Control, 'control')
export const EyeDropperTrigger = withContext<
  HTMLButtonElement,
  Assign<HTMLStyledProps<'button'>, ColorPicker.EyeDropperTriggerBaseProps>
>(ColorPicker.EyeDropperTrigger, 'eyeDropperTrigger')
export const FormatSelect = withContext<
  HTMLSelectElement,
  Assign<HTMLStyledProps<'select'>, ColorPicker.FormatSelectBaseProps>
>(ColorPicker.FormatSelect, 'formatSelect')
export const FormatTrigger = withContext<
  HTMLButtonElement,
  Assign<HTMLStyledProps<'button'>, ColorPicker.FormatTriggerBaseProps>
>(ColorPicker.FormatTrigger, 'formatTrigger')
export const Label = withContext<
  HTMLLabelElement,
  Assign<HTMLStyledProps<'label'>, ColorPicker.LabelBaseProps>
>(ColorPicker.Label, 'label')
export const Positioner = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.PositionerBaseProps>
>(ColorPicker.Positioner, 'positioner')
export const SwatchGroup = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.SwatchGroupBaseProps>
>(ColorPicker.SwatchGroup, 'swatchGroup')
export const SwatchIndicator = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.SwatchIndicatorBaseProps>
>(ColorPicker.SwatchIndicator, 'swatchIndicator')
export const Swatch = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.SwatchBaseProps>
>(ColorPicker.Swatch, 'swatch')
export const SwatchTrigger = withContext<
  HTMLButtonElement,
  Assign<HTMLStyledProps<'button'>, ColorPicker.SwatchTriggerBaseProps>
>(ColorPicker.SwatchTrigger, 'swatchTrigger')
export const TransparencyGrid = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.TransparencyGridBaseProps>
>(ColorPicker.TransparencyGrid, 'transparencyGrid')
export const Trigger = withContext<
  HTMLButtonElement,
  Assign<HTMLStyledProps<'button'>, ColorPicker.TriggerBaseProps>
>(ColorPicker.Trigger, 'trigger')
export const ValueSwatch = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.ValueSwatchBaseProps>
>(ColorPicker.ValueSwatch, 'swatch')
export const ValueText = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'span'>, ColorPicker.ValueTextBaseProps>
>(ColorPicker.ValueText, 'valueText')
export const View = withContext<
  HTMLDivElement,
  Assign<HTMLStyledProps<'div'>, ColorPicker.ViewBaseProps>
>(ColorPicker.View, 'view')
export {
  ColorPickerContext as Context,
  ColorPickerHiddenInput as HiddenInput,
} from '@ark-ui/react/color-picker'
import { type Assign, ColorPicker } from '@ark-ui/solid'
import type { ComponentProps } from 'solid-js'
import { type ColorPickerVariantProps, colorPicker } from 'styled-system/recipes'
import type { HTMLStyledProps } from 'styled-system/types'
import { createStyleContext } from '~/lib/create-style-context'
const { withProvider, withContext } = createStyleContext(colorPicker)
export type RootProviderProps = ComponentProps<typeof RootProvider>
export const RootProvider = withProvider<
  Assign<Assign<HTMLStyledProps<'div'>, ColorPicker.RootProviderBaseProps>, ColorPickerVariantProps>
>(ColorPicker.RootProvider, 'root')
export type RootProps = ComponentProps<typeof Root>
export const Root = withProvider<
  Assign<Assign<HTMLStyledProps<'div'>, ColorPicker.RootBaseProps>, ColorPickerVariantProps>
>(ColorPicker.Root, 'root')
export const AreaBackground = withContext<
  Assign<HTMLStyledProps<'div'>, ColorPicker.AreaBackgroundBaseProps>
>(ColorPicker.AreaBackground, 'areaBackground')
export const Area = withContext<Assign<HTMLStyledProps<'div'>, ColorPicker.AreaBaseProps>>(
  ColorPicker.Area,
  'area',
)
export const AreaThumb = withContext<
  Assign<HTMLStyledProps<'div'>, ColorPicker.AreaThumbBaseProps>
>(ColorPicker.AreaThumb, 'areaThumb')
export const ChannelInput = withContext<
  Assign<HTMLStyledProps<'input'>, ColorPicker.ChannelInputBaseProps>
>(ColorPicker.ChannelInput, 'channelInput')
export const ChannelSliderLabel = withContext<
  Assign<HTMLStyledProps<'label'>, ColorPicker.ChannelSliderLabelBaseProps>
>(ColorPicker.ChannelSliderLabel, 'channelSliderLabel')
export const ChannelSlider = withContext<
  Assign<HTMLStyledProps<'div'>, ColorPicker.ChannelSliderBaseProps>
>(ColorPicker.ChannelSlider, 'channelSlider')
export const ChannelSliderThumb = withContext<
  Assign<HTMLStyledProps<'div'>, ColorPicker.ChannelSliderThumbBaseProps>
>(ColorPicker.ChannelSliderThumb, 'channelSliderThumb')
export const ChannelSliderTrack = withContext<
  Assign<HTMLStyledProps<'div'>, ColorPicker.ChannelSliderTrackBaseProps>
>(ColorPicker.ChannelSliderTrack, 'channelSliderTrack')
export const ChannelSliderValueText = withContext<
  Assign<HTMLStyledProps<'span'>, ColorPicker.ChannelSliderValueTextBaseProps>
>(ColorPicker.ChannelSliderValueText, 'channelSliderValueText')
export const Content = withContext<Assign<HTMLStyledProps<'div'>, ColorPicker.ContentBaseProps>>(
  ColorPicker.Content,
  'content',
)
export const Control = withContext<Assign<HTMLStyledProps<'div'>, ColorPicker.ControlBaseProps>>(
  ColorPicker.Control,
  'control',
)
export const EyeDropperTrigger = withContext<
  Assign<HTMLStyledProps<'button'>, ColorPicker.EyeDropperTriggerBaseProps>
>(ColorPicker.EyeDropperTrigger, 'eyeDropperTrigger')
export const FormatSelect = withContext<
  Assign<HTMLStyledProps<'select'>, ColorPicker.FormatSelectBaseProps>
>(ColorPicker.FormatSelect, 'formatSelect')
export const FormatTrigger = withContext<
  Assign<HTMLStyledProps<'button'>, ColorPicker.FormatTriggerBaseProps>
>(ColorPicker.FormatTrigger, 'formatTrigger')
export const Label = withContext<Assign<HTMLStyledProps<'label'>, ColorPicker.LabelBaseProps>>(
  ColorPicker.Label,
  'label',
)
export const Positioner = withContext<
  Assign<HTMLStyledProps<'div'>, ColorPicker.PositionerBaseProps>
>(ColorPicker.Positioner, 'positioner')
export const SwatchGroup = withContext<
  Assign<HTMLStyledProps<'div'>, ColorPicker.SwatchGroupBaseProps>
>(ColorPicker.SwatchGroup, 'swatchGroup')
export const SwatchIndicator = withContext<
  Assign<HTMLStyledProps<'div'>, ColorPicker.SwatchIndicatorBaseProps>
>(ColorPicker.SwatchIndicator, 'swatchIndicator')
export const Swatch = withContext<Assign<HTMLStyledProps<'div'>, ColorPicker.SwatchBaseProps>>(
  ColorPicker.Swatch,
  'swatch',
)
export const SwatchTrigger = withContext<
  Assign<HTMLStyledProps<'button'>, ColorPicker.SwatchTriggerBaseProps>
>(ColorPicker.SwatchTrigger, 'swatchTrigger')
export const TransparencyGrid = withContext<
  Assign<HTMLStyledProps<'div'>, ColorPicker.TransparencyGridBaseProps>
>(ColorPicker.TransparencyGrid, 'transparencyGrid')
export const Trigger = withContext<Assign<HTMLStyledProps<'button'>, ColorPicker.TriggerBaseProps>>(
  ColorPicker.Trigger,
  'trigger',
)
export const ValueSwatch = withContext<
  Assign<HTMLStyledProps<'div'>, ColorPicker.ValueSwatchBaseProps>
>(ColorPicker.ValueSwatch, 'swatch')
export const ValueText = withContext<
  Assign<HTMLStyledProps<'span'>, ColorPicker.ValueTextBaseProps>
>(ColorPicker.ValueText, 'valueText')
export const View = withContext<Assign<HTMLStyledProps<'div'>, ColorPicker.ViewBaseProps>>(
  ColorPicker.View,
  'view',
)
export {
  ColorPickerContext as Context,
  ColorPickerHiddenInput as HiddenInput,
} from '@ark-ui/solid'
No snippet foundExtend ~/components/ui/primitives/index.ts with the following line:
export * as ColorPicker from './color-picker'2
Integrate Recipe
If you're not using @park-ui/preset, add the following recipe to yourpanda.config.ts:
import { colorPickerAnatomy } from '@ark-ui/anatomy'
import { defineSlotRecipe } from '@pandacss/dev'
export const colorPicker = defineSlotRecipe({
  className: 'colorPicker',
  slots: colorPickerAnatomy.keys(),
  base: {
    root: {
      display: 'flex',
      flexDirection: 'column',
      gap: '1.5',
    },
    label: {
      color: 'fg.default',
      fontWeight: 'medium',
      textStyle: 'sm',
    },
    control: {
      display: 'flex',
      flexDirection: 'row',
      gap: '2',
    },
    content: {
      background: 'bg.default',
      borderRadius: 'l3',
      boxShadow: 'lg',
      display: 'flex',
      flexDirection: 'column',
      maxWidth: 'sm',
      p: '4',
      zIndex: 'dropdown',
      _open: {
        animation: 'fadeIn 0.25s ease-out',
      },
      _closed: {
        animation: 'fadeOut 0.2s ease-out',
      },
      _hidden: {
        display: 'none',
      },
    },
    area: {
      height: '36',
      borderRadius: 'l2',
      overflow: 'hidden',
    },
    areaThumb: {
      borderRadius: 'full',
      height: '2.5',
      width: '2.5',
      boxShadow: 'white 0px 0px 0px 2px, black 0px 0px 2px 1px',
      outline: 'none',
    },
    areaBackground: {
      height: 'full',
    },
    channelSlider: {
      borderRadius: 'l2',
    },
    channelSliderTrack: {
      height: '3',
      borderRadius: 'l2',
    },
    swatchGroup: {
      display: 'grid',
      gridTemplateColumns: 'repeat(7, 1fr)',
      gap: '2',
      background: 'bg.default',
    },
    swatch: {
      height: '6',
      width: '6',
      borderRadius: 'l2',
      boxShadow:
        '0 0 0 1px var(--colors-border-emphasized), 0 0 0 2px var(--colors-bg-default) inset',
    },
    channelSliderThumb: {
      borderRadius: 'full',
      height: '2.5',
      width: '2.5',
      boxShadow: 'white 0px 0px 0px 2px, black 0px 0px 2px 1px',
      transform: 'translate(-50%, -50%)',
      outline: 'none',
    },
    transparencyGrid: {
      borderRadius: 'l2',
    },
  },
})