Color Picker
A component that allows users to select a color from a predefined set.
'use client'
import { PipetteIcon } from 'lucide-react'
import { HStack, Stack } from 'styled-system/jsx'
import { ColorPicker } from '~/components/ui/color-picker'
import { IconButton } from '~/components/ui/icon-button'
import { Input } from '~/components/ui/input'
import { Text } from '~/components/ui/text'
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%)',
]
import { PipetteIcon } from 'lucide-solid'
import { For } from 'solid-js'
import { HStack, Stack } from 'styled-system/jsx'
import { ColorPicker } from '~/components/ui/color-picker'
import { IconButton } from '~/components/ui/icon-button'
import { Input } from '~/components/ui/input'
import { Text } from '~/components/ui/text'
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={(inputProps) => <Input {...inputProps()} />}
/>
<ColorPicker.Trigger
asChild={(triggerProps) => (
<IconButton variant="outline" {...triggerProps()}>
<ColorPicker.Swatch value={api().value} />
</IconButton>
)}
/>
</ColorPicker.Control>
<ColorPicker.Positioner>
<ColorPicker.Content>
<Stack gap="3">
<ColorPicker.Area>
<ColorPicker.AreaBackground />
<ColorPicker.AreaThumb />
</ColorPicker.Area>
<HStack gap="3">
<ColorPicker.EyeDropperTrigger
asChild={(triggerProps) => (
<IconButton
size="xs"
variant="outline"
aria-label="Pick a color"
{...triggerProps()}
>
<PipetteIcon />
</IconButton>
)}
/>
<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={(inputProps) => <Input size="2xs" {...inputProps()} />}
/>
<ColorPicker.ChannelInput
channel="alpha"
asChild={(inputProps) => <Input size="2xs" {...inputProps()} />}
/>
</HStack>
<Stack gap="1.5">
<Text size="xs" fontWeight="medium" color="fg.default">
Saved Colors
</Text>
<ColorPicker.SwatchGroup>
<For each={presets}>
{(color) => (
<ColorPicker.SwatchTrigger value={color}>
<ColorPicker.Swatch value={color} />
</ColorPicker.SwatchTrigger>
)}
</For>
</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%)',
]
Usage
import { ColorPicker } from '~/components/ui/color-picker'
Installation
npx @park-ui/cli components add color-picker
1
Add Styled Primitive
Copy the code snippet below into ~/components/ui/styled/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 './utils/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 './utils/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 found
2
Add Re-Export
To improve the developer experience, re-export the styled primitives in~/components/ui/color-picker.tsx
.
export * as ColorPicker from './styled/color-picker'
export * as ColorPicker from './styled/color-picker'
3
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',
},
},
})