SvColorInput
A color swatch that opens a portalled popover with a hex field, the native picker, and a preset palette.
SvColorInput shows the current color as a swatch with its hex value; clicking it
opens an animated popover carrying a hex text field, the browser's native color
picker, and a grid of preset swatches. The popover is portalled to <body> and
anchored to the trigger, so it escapes the grid's scroll container and never
clips. It emits a normalized hex string and is the styled renderer over the
headless createColorInput core. Its label / hint / error chrome comes from
SvField.
Related: SvTextInput · SvTagsInput · Inputs overview
Installation
Add it with the CLI - this drops a ready-to-edit SvColorInput starter into your app:
Prefer to see it first? npx @svgrid/ui try color-input opens it in a throwaway sandbox - no project needed.
Or install the package and import it directly. SvColorInput ships free in
@svgrid/grid and is part of the grid's editor kit - the same control SvGrid mounts when you edit a matching cell:
The examples on this page import from @svgrid/grid:
<script lang="ts">
import { SvColorInput } from '@svgrid/grid'
// The bound value behind each example below.
let accent = $state('')
</script>
import { SvColorInput } from '@svgrid/grid'
Example
Open the live example: Color input (Inputs)
<script lang="ts">
import { SvColorInput } from '@svgrid/grid'
let color = $state('#3b82f6')
</script>
<SvColorInput label="Brand color" bind:value={color} />
Props
SvColorInput extends the shared SvEditorProps (disabled, readonly,
required, invalid, error, label, hint, size, dir, name, id,
ariaLabel) and adds:
| Prop | Type | Default | Description |
|---|---|---|---|
value |
string |
#3b82f6 |
The hex color. Bindable with bind:value. |
onChange |
(hex: string) => void |
- | Fires with the normalized hex on change. |
palette |
string[] |
- | Preset swatches shown in the popover. |
autoOpen |
boolean |
false |
Focus the trigger and open on mount. |
messages |
Partial<ColorMessages> |
- | Override the built-in popover strings. |
block |
boolean |
false |
Stretch to the container width (else hugs its content). |
The box, size, invalid state and focus ring are owned by SvField's
shared frame chrome.
ColorMessages is { dialog; picker; hex }.
Examples
Custom preset palette
Pass your brand's swatches as palette so the popover offers on-brand choices
first:
<SvColorInput
bind:value={accent}
palette={['#0ea5e9', '#8b5cf6', '#f59e0b', '#10b981', '#ef4444']}
/>
Open immediately as a cell editor
Set autoOpen when mounting inside a grid cell so the popover appears the moment
editing starts:
<SvColorInput bind:value={row.color} autoOpen />
Live-retheme the grid from a swatch
The component emits a normalized hex, so wire onChange straight into the grid's
--sg-accent token for an instant theme preview:
<script lang="ts">
import { SvColorInput } from '@svgrid/grid'
let accent = $state('#2563eb')
function apply(hex: string) {
document.documentElement.style.setProperty('--sg-accent', hex)
}
</script>
<SvColorInput
label="Grid accent"
bind:value={accent}
onChange={apply}
palette={['#2563eb', '#7c3aed', '#db2777', '#ea580c', '#16a34a']}
/>
Tip: onChange always hands you the normalized hex (whether the user typed it,
used the native picker, or clicked a preset), so you never have to sanitize the
value before storing it.
Accessibility
- The trigger is a real
<button>with a focus ring; the popover isrole="dialog"with adialogaria-labelfrommessages. - The hex field, native picker, and each palette chip carry their own
aria-labels; the active swatch is outlined. - The popover closes on outside pointer-down and repositions on scroll and resize, so it stays anchored to the swatch.
More examples
Color input - headless
createColorInput drives the portalled SvColorInput and a custom inline swatch + palette panel.
Open the live example: Color input - headless (Headless Editors)
Sizes
Every control takes the same three sizes, so a dense toolbar and a roomy form can share components.
<script lang="ts">
import { SvColorInput } from '@svgrid/grid'
let color = $state('')
</script>
<SvColorInput bind:value={color} size="sm" />
<SvColorInput bind:value={color} size="md" />
<SvColorInput bind:value={color} size="lg" />
In a form
The shared field props behave the same on every editor: label names it, hint explains it, and error plus invalid mark it - which is why a validated form does not need per-component handling.
<script lang="ts">
import { SvColorInput } from '@svgrid/grid'
let color = $state('')
</script>
<SvColorInput
bind:value={color}
label="Label"
hint="A short hint"
required
/>
<SvColorInput
bind:value={color}
label="Label"
error="Something is wrong"
invalid
/>
See also
- Inputs overview - the whole input family at a glance.
- SvTextInput - the base single-line field.
- SvTagsInput - a chips-style value editor.
Live examples
- Color input - SvColorInput on its own: a swatch that opens an animated, portalled popover with a hex field, the native picker and a preset palette. Emits a hex string.
- Color input - headless - createColorInput drives the portalled SvColorInput and a custom inline swatch + palette panel.