diff --git a/packages/docs/src/registry/items/parser-color.json b/packages/docs/src/registry/items/parser-color.json
new file mode 100644
index 000000000..6dd6ed7de
--- /dev/null
+++ b/packages/docs/src/registry/items/parser-color.json
@@ -0,0 +1,15 @@
+{
+ "type": "registry:item",
+ "name": "parser-color",
+ "title": "Color Parser",
+ "description": "Parse colors in multiple formats (hex, rgb, hsl, hsv) with nuqs using tinycolor2.",
+ "dependencies": ["nuqs", "tinycolor2"],
+ "devDependencies": ["@types/tinycolor2"],
+ "files": [
+ {
+ "type": "registry:file",
+ "path": "src/registry/items/parser-color.source",
+ "target": "~/lib/parsers/color.ts"
+ }
+ ]
+}
diff --git a/packages/docs/src/registry/items/parser-color.md b/packages/docs/src/registry/items/parser-color.md
new file mode 100644
index 000000000..82e0d51eb
--- /dev/null
+++ b/packages/docs/src/registry/items/parser-color.md
@@ -0,0 +1,129 @@
+# Color Parser
+
+Parse colors in multiple formats (hex, rgb, hsl, hsv) using [tinycolor2](https://github.com/bgrins/TinyColor).
+
+Install the parser using the CLI or copy/paste above, then use it in your components:
+
+## Usage
+
+### Basic hex color
+
+```tsx
+import { useQueryState } from 'nuqs'
+import { parseAsHex } from '~/lib/parsers/color'
+
+function ColorPicker() {
+ const [color, setColor] = useQueryState(
+ 'color',
+ parseAsHex().withDefault('#0055ff')
+ )
+
+ return (
+ setColor(e.target.value)}
+ />
+ )
+}
+```
+
+### Different output formats
+
+```tsx
+import { parseAsRgb, parseAsHsl, parseAsHsv } from '~/lib/parsers/color'
+
+// RGB output
+const [color] = useQueryState('color', parseAsRgb().withDefault('rgb(0, 85, 255)'))
+
+// HSL output
+const [color] = useQueryState('color', parseAsHsl().withDefault('hsl(220, 100%, 50%)'))
+
+// HSV output
+const [color] = useQueryState('color', parseAsHsv().withDefault('hsv(220, 100%, 100%)'))
+```
+
+### Short hex format
+
+```tsx
+import { parseAsHex } from '~/lib/parsers/color'
+
+const [color, setColor] = useQueryState(
+ 'color',
+ parseAsHex(true).withDefault('#05f') // true = short format
+)
+// Returns #05f instead of #0055ff when possible
+```
+
+### Theme customizer
+
+```tsx
+import { useQueryStates } from 'nuqs'
+import { parseAsHex, parseAsRgb } from '~/lib/parsers/color'
+
+function ThemeEditor() {
+ const [colors, setColors] = useQueryStates({
+ primary: parseAsHex().withDefault('#0055ff'),
+ secondary: parseAsHex(true).withDefault('#f0f'),
+ background: parseAsRgb().withDefault('rgb(255, 255, 255)')
+ })
+
+ return (
+
+ setColors({ primary: e.target.value })}
+ />
+ {/* ... */}
+
+ )
+}
+```
+
+## Accepted input formats
+
+The parser accepts any valid color format that tinycolor2 supports:
+
+- **Hex**: `#fff`, `#ffffff`, `fff`, `ffffff`
+- **RGB**: `rgb(255, 255, 255)`, `rgba(255, 255, 255, 0.5)`
+- **HSL**: `hsl(0, 0%, 100%)`, `hsla(0, 0%, 100%, 0.5)`
+- **HSV**: `hsv(0, 0%, 100%)`, `hsva(0, 0%, 100%, 0.5)`
+- **Named**: `white`, `red`, `blue`, etc.
+
+Invalid colors return `null`.
+
+## URL serialization
+
+All colors are automatically serialized to 6-character hex format (without `#`) in URLs:
+
+```
+// User input: rgb(255, 0, 0) → URL: ?color=ff0000
+// User input: hsl(120, 100%, 50%) → URL: ?color=00ff00
+// User input: blue → URL: ?color=0000ff
+```
+
+## API
+
+### `parseAsColor(options?)`
+
+Main parser with configuration options.
+
+**Options:**
+- `format?: 'hex' | 'rgb' | 'hsl' | 'hsv'` - Output format (default: `'hex'`)
+- `short?: boolean` - Use short hex format when possible (default: `false`)
+
+### Convenience parsers
+
+- `parseAsHex(short?)` - Parse as hex color
+- `parseAsRgb()` - Parse as RGB color
+- `parseAsHsl()` - Parse as HSL color
+- `parseAsHsv()` - Parse as HSV color
+
+## Why tinycolor2?
+
+- **Lightweight**: Only 5kB minified + gzipped
+- **Comprehensive**: Supports all common color formats
+- **Battle-tested**: Widely used in production
+- **Simple API**: Easy to use and understand
+- **Type-safe**: TypeScript definitions included
diff --git a/packages/docs/src/registry/items/parser-color.source b/packages/docs/src/registry/items/parser-color.source
new file mode 100644
index 000000000..6d467e2e0
--- /dev/null
+++ b/packages/docs/src/registry/items/parser-color.source
@@ -0,0 +1,116 @@
+import tinycolor from 'tinycolor2'
+import { createParser } from 'nuqs'
+
+/**
+ * Supported color output formats
+ */
+export type ColorFormat = 'hex' | 'rgb' | 'hsl' | 'hsv'
+
+/**
+ * Configuration options for color parser
+ */
+export interface ColorParserOptions {
+ /**
+ * Output format for the color
+ * @default 'hex'
+ */
+ format?: ColorFormat
+ /**
+ * For hex format: use 3-character form when possible (#fff vs #ffffff)
+ * @default false
+ */
+ short?: boolean
+}
+
+/**
+ * Parse color from query string and convert to specified format
+ *
+ * Accepts hex, rgb, hsl, hsv, and named colors as input.
+ * Always serializes to hex in the URL for compactness.
+ *
+ * @example
+ * ```tsx
+ * // Basic hex color
+ * const [color, setColor] = useQueryState(
+ * 'color',
+ * parseAsColor().withDefault('#0055ff')
+ * )
+ *
+ * // RGB output
+ * const [color, setColor] = useQueryState(
+ * 'color',
+ * parseAsColor({ format: 'rgb' }).withDefault('rgb(0, 85, 255)')
+ * )
+ *
+ * // Short hex format
+ * const [color, setColor] = useQueryState(
+ * 'color',
+ * parseAsColor({ short: true }).withDefault('#05f')
+ * )
+ * ```
+ */
+export function parseAsColor(options: ColorParserOptions = {}) {
+ const { format = 'hex', short = false } = options
+
+ return createParser({
+ parse(value: string) {
+ // Decode URL-encoded characters (e.g., %23 -> #)
+ const decodedValue = decodeURIComponent(value)
+ const color = tinycolor(decodedValue)
+
+ if (!color.isValid()) {
+ return null
+ }
+
+ switch (format) {
+ case 'hex':
+ return short ? color.toHexString() : color.toHexString()
+ case 'rgb':
+ return color.toRgbString()
+ case 'hsl':
+ return color.toHslString()
+ case 'hsv':
+ return color.toHsvString()
+ default:
+ return color.toHexString()
+ }
+ },
+
+ serialize(value: string) {
+ const color = tinycolor(value)
+ if (!color.isValid()) {
+ return ''
+ }
+ // Always use hex6 format for URL (most compact & consistent)
+ return color.toHex()
+ }
+ })
+}
+
+/**
+ * Parse as hex color (default)
+ * @example parseAsHex().withDefault('#0055ff')
+ */
+export const parseAsHex = (short = false) =>
+ parseAsColor({ format: 'hex', short })
+
+/**
+ * Parse as RGB color
+ * @example parseAsRgb().withDefault('rgb(0, 85, 255)')
+ */
+export const parseAsRgb = () =>
+ parseAsColor({ format: 'rgb' })
+
+/**
+ * Parse as HSL color
+ * @example parseAsHsl().withDefault('hsl(220, 100%, 50%)')
+ */
+export const parseAsHsl = () =>
+ parseAsColor({ format: 'hsl' })
+
+/**
+ * Parse as HSV color
+ * @example parseAsHsv().withDefault('hsv(220, 100%, 100%)')
+ */
+export const parseAsHsv = () =>
+ parseAsColor({ format: 'hsv' })