halo-color-picker
v0.1.0
Published
A tiny, animated radial color picker for React. Swatches bloom outward from a single core in a halo of color.
Maintainers
Readme
Halo Color Picker
A tiny, beautiful, animated radial color picker for React. Tap the core and watch a beautifully animated disc spring open into a radiant color wheel.
Extracted from stele.so
I couldn't find a color picker with the exact radial physics and premium feel I needed for my spatial UI canvas. So, I reverse-engineered the best one I'd ever seen and open-sourced it for the community.
🎨 Features at a glance
- Fluid Animations: Beautiful fisheye magnification and spring physics.
- Zero Dependencies: Exceptionally lightweight.
- Universal Compatibility: Flawlessly supports all React versions
>=16.8.0 - Beautiful by Default: Auto-arranges swatches into a geometric flower pattern.
- Fully Accessible: Keyboard navigation, focus trapping, and smooth mobile touch interactions out of the box.
- Strictly Typed: Built with TypeScript for a flawless developer experience.
Getting Started
Install the package using your favorite package manager:
bun add halo-color-picker
# or
npm install halo-color-picker
# or
yarn add halo-color-picker
# or
pnpm add halo-color-pickerQuick Integration
Integrating Halo into your React application takes only a few lines of code.
import { useState } from 'react';
import { HaloColorPicker, type HaloColor } from 'halo-color-picker';
import 'halo-color-picker/styles.css'; // Import the minimal stylesheet once
export default function App() {
const [color, setColor] = useState<HaloColor>();
return (
<HaloColorPicker
defaultValue="#3b82f6"
onChange={setColor}
/>
);
}Usage Guide
Halo Color Picker is designed to be highly flexible while keeping the API surface minimal.
Controlled State
If you need to strictly control the color or the open/closed state of the picker, use the value and open props.
const [hexString, setHexString] = useState('#22c55e');
const [isOpen, setIsOpen] = useState(false);
<HaloColorPicker
value={hexString}
onChange={(color) => setHexString(color.hex)}
open={isOpen}
onOpenChange={setIsOpen}
/>Custom Color Swatches
You can provide your own curated palette instead of the default spectrum. Halo intelligently accepts Hex, RGB(A), HSL(A) strings, or raw color objects.
<HaloColorPicker
swatches={[
'#0ea5e9',
'#6366f1',
'#ec4899',
{ h: 140, s: 70, l: 50 } // Objects are supported too!
]}
/>AI Assistance
Want to use an AI assistant to build with this library? We provide a standard llms.txt file optimized for LLMs.
Just feed this URL to Claude, or Cursor to give it instant, perfect context on how to use halo-color-picker:
https://akashtdev.github.io/halo-color-picker/llms.txtAPI Reference
Component Props
Configure the look and feel of your color picker using these properties.
| Property | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| value | ColorInput | — | The controlled color value. |
| defaultValue | ColorInput | '#3b82f6' | The initial color when uncontrolled. |
| swatches | ColorInput[] | (Default Wheel) | Array of colors to display in the radial disc. |
| onChange | (color: HaloColor) => void | — | Callback fired when a color is selected. |
| open | boolean | — | Controlled visibility state of the disc. |
| defaultOpen | boolean | false | Initial visibility state when uncontrolled. |
| onOpenChange | (open: boolean) => void| — | Callback fired when the disc opens or closes. |
| trigger | 'click' \| 'hover' | 'click' | Interaction required to open the disc. |
| closeOnSelect| boolean | true | Automatically collapse the disc after selection. |
| disabled | boolean | false | Disables interaction and dims the trigger. |
| coreSize | number | 36 | Diameter of the center trigger button (in px). |
| swatchSize | number | 30 | Diameter of each individual swatch (in px). |
| duration | number | 260 | Animation duration for opening/closing (in ms). |
| glow | boolean | true | Enables a soft colored glow under the hovered swatch. |
| magnify | 'none' \| 'focus' \| 'dock' | 'focus' | Hover effect style. 'focus' enlarges the single hovered swatch, 'dock' swells the surrounding area (like macOS dock), 'none' disables it. |
| placement | 'top' \| 'bottom' \| 'auto' | 'auto' | Origin point where the disc expands relative to the trigger. |
| morph | boolean | false | Expands the trigger into the disc center. |
| liftOnHover | boolean | false | Brings the hovered swatch to the top layer. |
| portal | boolean | true | Renders the popover in a React Portal (document.body) so it's never cut off by parent containers. |
| gap | number | 0 | Spacing between swatches. 0 allows slight overlap. |
| label | string | 'Choose a color'| ARIA label for screen readers. |
| className | string | — | Extra CSS class applied to the root element. |
| style | CSSProperties | — | Inline style applied to the root element. |
The HaloColor Object
When a selection is made, the onChange callback provides a comprehensive HaloColor object, giving you the exact format you need instantly without external converters.
interface HaloColor {
hex: string; // e.g. "#3b82f6"
rgb: string; // e.g. "rgb(59, 130, 246)"
rgba: string; // e.g. "rgba(59, 130, 246, 1)"
hsl: string; // e.g. "hsl(217, 91%, 60%)"
hsla: string; // e.g. "hsla(217, 91%, 60%, 1)"
r: number; g: number; b: number; a: number; // Channels (a is 0-1)
h: number; s: number; l: number;
}License
MIT © Akash T
