Introduction
Components
- Accordion
- Action Sheet
- Alert
- Audio Player
- Audio Recorder
- Audio Waveform
- Avatar
- Badge
- BottomSheet
- Button
- Camera
- Camera Preview
- Card
- Carousel
- Checkbox
- Collapsible
- Color Picker
- Combobox
- Date Picker
- File Picker
- Gallery
- Hello Wave
- Icon
- Image
- Input
- Input OTP
- Link
- MediaPicker
- Mode Toggle
- Onboarding
- ParallaxScrollView
- Picker
- Popover
- Progress
- Radio
- ScrollView
- SearchBar
- Separator
- Share
- Sheet
- Skeleton
- Spinner
- Switch
- Table
- Tabs
- Text
- Toast
- Toggle
- Video
- View
Charts
import { ColorPicker } from '@/components/ui/color-picker';
import React, { useState } from 'react';
export function ColorPickerDemo() {
const [color, setColor] = useState('#ff0000');
return (
<ColorPicker
value={color}
onColorChange={setColor}
onColorSelect={(selectedColor) => {
console.log('Color selected:', selectedColor);
setColor(selectedColor);
}}
/>
);
}
Installation
pnpm dlx bna-ui add color-picker
Usage
import { ColorPicker, ColorSwatch } from '@/components/ui/color-picker';
<ColorPicker
value='#ff0000'
onColorChange={(color) => console.log('Color changed:', color)}
onColorSelect={(color) => console.log('Color selected:', color)}
/>
Examples
Default
import { ColorPicker } from '@/components/ui/color-picker';
import React, { useState } from 'react';
export function ColorPickerDemo() {
const [color, setColor] = useState('#ff0000');
return (
<ColorPicker
value={color}
onColorChange={setColor}
onColorSelect={(selectedColor) => {
console.log('Color selected:', selectedColor);
setColor(selectedColor);
}}
/>
);
}
Different Sizes
import { ColorPicker } from '@/components/ui/color-picker';
import { View } from '@/components/ui/view';
import React, { useState } from 'react';
export function ColorPickerSizes() {
const [smallColor, setSmallColor] = useState('#ff6b6b');
const [mediumColor, setMediumColor] = useState('#4ecdc4');
const [largeColor, setLargeColor] = useState('#45b7d1');
const [xlColor, setXlColor] = useState('#f9ca24');
return (
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 16 }}>
<ColorPicker
value={smallColor}
onColorChange={setSmallColor}
onColorSelect={setSmallColor}
swatchSize={24}
/>
<ColorPicker
value={mediumColor}
onColorChange={setMediumColor}
onColorSelect={setMediumColor}
swatchSize={32}
/>
<ColorPicker
value={largeColor}
onColorChange={setLargeColor}
onColorSelect={setLargeColor}
swatchSize={48}
/>
<ColorPicker
value={xlColor}
onColorChange={setXlColor}
onColorSelect={setXlColor}
swatchSize={64}
/>
</View>
);
}
With Initial Colors
import { ColorPicker } from '@/components/ui/color-picker';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React, { useState } from 'react';
export function ColorPickerColors() {
const [redColor, setRedColor] = useState('#e74c3c');
const [greenColor, setGreenColor] = useState('#2ecc71');
const [blueColor, setBlueColor] = useState('#3498db');
const [purpleColor, setPurpleColor] = useState('#9b59b6');
const [orangeColor, setOrangeColor] = useState('#f39c12');
const colorData = [
{ name: 'Red', color: redColor, setter: setRedColor },
{ name: 'Green', color: greenColor, setter: setGreenColor },
{ name: 'Blue', color: blueColor, setter: setBlueColor },
{ name: 'Purple', color: purpleColor, setter: setPurpleColor },
{ name: 'Orange', color: orangeColor, setter: setOrangeColor },
];
return (
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 16 }}>
{colorData.map(({ name, color, setter }) => (
<View key={name} style={{ alignItems: 'center', gap: 8 }}>
<ColorPicker
value={color}
onColorChange={setter}
onColorSelect={setter}
swatchSize={40}
/>
<Text variant='caption'>{name}</Text>
</View>
))}
</View>
);
}
Disabled State
import { ColorPicker } from '@/components/ui/color-picker';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React from 'react';
export function ColorPickerDisabled() {
return (
<View style={{ alignItems: 'center', gap: 12 }}>
<ColorPicker value='#6c757d' disabled={true} swatchSize={48} />
<Text variant='caption' style={{ opacity: 0.6 }}>
Disabled Color Picker
</Text>
</View>
);
}
Color Swatch Only
import { ColorSwatch } from '@/components/ui/color-picker';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React, { useState } from 'react';
export function ColorSwatchDemo() {
const [selectedColor, setSelectedColor] = useState('#e74c3c');
const colors = [
'#e74c3c',
'#3498db',
'#2ecc71',
'#f39c12',
'#9b59b6',
'#1abc9c',
'#e67e22',
'#34495e',
];
return (
<View style={{ alignItems: 'center', gap: 16 }}>
<View
style={{
flexDirection: 'row',
flexWrap: 'wrap',
gap: 8,
justifyContent: 'center',
}}
>
{colors.map((color) => (
<ColorSwatch
key={color}
color={color}
size={36}
onPress={() => setSelectedColor(color)}
style={{
borderWidth: selectedColor === color ? 3 : 2,
borderColor: selectedColor === color ? '#000' : 'transparent',
}}
/>
))}
</View>
<Text variant='body'>Selected: {selectedColor.toUpperCase()}</Text>
</View>
);
}
Custom Styling
import { ColorPicker } from '@/components/ui/color-picker';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React, { useState } from 'react';
export function ColorPickerStyled() {
const [primaryColor, setPrimaryColor] = useState('#007AFF');
const [accentColor, setAccentColor] = useState('#FF3B30');
return (
<View style={{ gap: 20 }}>
{/* Rounded Square Style */}
<View style={{ alignItems: 'center', gap: 8 }}>
<ColorPicker
value={primaryColor}
onColorChange={setPrimaryColor}
onColorSelect={setPrimaryColor}
swatchSize={50}
style={{
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.25,
shadowRadius: 4,
elevation: 5,
}}
/>
<Text variant='caption'>Primary Color</Text>
</View>
{/* With Custom Border */}
<View style={{ alignItems: 'center', gap: 8 }}>
<View
style={{
padding: 4,
borderRadius: 30,
borderWidth: 2,
borderColor: '#ddd',
backgroundColor: '#fff',
}}
>
<ColorPicker
value={accentColor}
onColorChange={setAccentColor}
onColorSelect={setAccentColor}
swatchSize={40}
/>
</View>
<Text variant='caption'>Accent Color</Text>
</View>
</View>
);
}
Color Palette
import { ColorPicker } from '@/components/ui/color-picker';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import { useThemeColor } from '@/hooks/useThemeColor';
import React, { useState } from 'react';
export function ColorPickerPalette() {
const cardColor = useThemeColor({}, 'card');
const [colors, setColors] = useState([
'#FF6B6B',
'#4ECDC4',
'#45B7D1',
'#F9CA24',
'#6C5CE7',
'#A29BFE',
'#FD79A8',
'#00B894',
]);
const updateColor = (index: number, newColor: string) => {
const newColors = [...colors];
newColors[index] = newColor;
setColors(newColors);
};
return (
<View
style={{
flexDirection: 'row',
flexWrap: 'wrap',
gap: 12,
justifyContent: 'center',
padding: 16,
backgroundColor: cardColor,
borderRadius: 12,
}}
>
{colors.map((color, index) => (
<View key={index} style={{ alignItems: 'center', gap: 4 }}>
<ColorPicker
value={color}
onColorChange={(newColor) => updateColor(index, newColor)}
onColorSelect={(newColor) => updateColor(index, newColor)}
swatchSize={36}
/>
<Text variant='caption' style={{ fontSize: 10 }}>
{color.toUpperCase()}
</Text>
</View>
))}
</View>
);
}
With Labels
import { ColorPicker } from '@/components/ui/color-picker';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React, { useState } from 'react';
export function ColorPickerLabeled() {
const [backgroundColor, setBackgroundColor] = useState('#ffffff');
const [textColor, setTextColor] = useState('#333333');
const [borderColor, setBorderColor] = useState('#e1e5e9');
return (
<View style={{ gap: 20 }}>
{/* Background Color */}
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>
<ColorPicker
value={backgroundColor}
onColorChange={setBackgroundColor}
onColorSelect={setBackgroundColor}
swatchSize={40}
/>
<View style={{ flex: 1 }}>
<Text variant='body' style={{ fontWeight: '600' }}>
Background Color
</Text>
<Text variant='caption' style={{ opacity: 0.7 }}>
{backgroundColor.toUpperCase()}
</Text>
</View>
</View>
{/* Text Color */}
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>
<ColorPicker
value={textColor}
onColorChange={setTextColor}
onColorSelect={setTextColor}
swatchSize={40}
/>
<View style={{ flex: 1 }}>
<Text variant='body' style={{ fontWeight: '600' }}>
Text Color
</Text>
<Text variant='caption' style={{ opacity: 0.7 }}>
{textColor.toUpperCase()}
</Text>
</View>
</View>
{/* Border Color */}
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>
<ColorPicker
value={borderColor}
onColorChange={setBorderColor}
onColorSelect={setBorderColor}
swatchSize={40}
/>
<View style={{ flex: 1 }}>
<Text variant='body' style={{ fontWeight: '600' }}>
Border Color
</Text>
<Text variant='caption' style={{ opacity: 0.7 }}>
{borderColor.toUpperCase()}
</Text>
</View>
</View>
{/* Preview */}
<View
style={{
padding: 16,
backgroundColor: backgroundColor,
borderWidth: 2,
borderColor: borderColor,
borderRadius: 8,
marginTop: 8,
}}
>
<Text style={{ color: textColor, textAlign: 'center' }}>
Preview with selected colors
</Text>
</View>
</View>
);
}
API Reference
ColorPicker
The main color picker component that displays a swatch and opens a modal for color selection.
Prop | Type | Default | Description |
---|---|---|---|
value | string | '#ff0000' | The current color value in hex format. |
onColorChange | (color: string) => void | - | Callback fired when the color changes during selection. |
onColorSelect | (color: string) => void | - | Callback fired when the user confirms color selection. |
swatchSize | number | HEIGHT | The size of the color swatch in pixels. |
disabled | boolean | false | Whether the color picker is disabled. |
style | ViewStyle | - | Additional styles to apply to the container. |
ColorSwatch
A standalone color swatch component that can be used independently.
Prop | Type | Default | Description |
---|---|---|---|
color | string | - | The color to display in hex format. |
size | number | 32 | The size of the swatch in pixels. |
style | ViewStyle | - | Additional styles to apply to the swatch. |
onPress | () => void | - | Callback fired when the swatch is pressed. |
Color Utilities
The component includes several utility functions for color manipulation:
hsvToRgb(h, s, v)
- Converts HSV values to RGBrgbToHex(r, g, b)
- Converts RGB values to hex stringhexToRgb(hex)
- Converts hex string to RGB valuesrgbToHsv(r, g, b)
- Converts RGB values to HSV
Features
- HSV Color Space: Uses HSV (Hue, Saturation, Value) color model for intuitive color selection
- Interactive Gestures: Pan gestures for hue bar and saturation/brightness picker
- Real-time Preview: Live color preview as you drag the selectors
- Modal Interface: Full-screen modal with cancel and confirm actions
- Customizable: Configurable swatch sizes and styling
- Accessible: Proper contrast and readable color values
- Smooth Animations: Powered by react-native-reanimated for smooth interactions
Accessibility
The ColorPicker component is built with accessibility in mind:
- Color values are displayed in uppercase hex format for easy reading
- High contrast knobs for better visibility
- Proper touch targets for gesture interactions
- Modal provides clear cancel and confirm actions
- Color preview shows the selected color prominently
Notes
- The component uses
expo-linear-gradient
for smooth color gradients - Gesture handling is powered by
react-native-gesture-handler
- Animations use
react-native-reanimated
for optimal performance - The hue bar uses SVG gradients for precise color representation
- Color calculations maintain precision across different color spaces