Fields
Color Field
The color field renders a color picker in the admin UI and stores the selected color as a CSS color string. Supported formats are hex ("#3b82f6"), rgb ("rgb(59, 130, 246)"), hsl ("hsl(217, 91%, 60%)"), and oklch ("oklch(0.63 0.18 252)"). Editors can switch between formats using a segmented control; the stored value always reflects the active format.
The underlying Convex validator is v.string(), wrapped in v.optional() unless marked as required.
An optional color field remains unset until an editor chooses a color. Clearing it restores the unset state instead of silently storing black.
Config options
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
required | boolean | false | Makes the field required in the schema and admin UI | |
readOnly | boolean | false | Renders the picker as non-editable | |
formats | Array<"hex" | "rgb" | "hsl" | "oklch"> | ["hex", "rgb", "hsl", "oklch"] | Which color formats the editor can use | |
placeholder | string | Placeholder text for the color input | ||
label | string | function | Field name | Custom label for the admin UI | |
description | string | Help text displayed below the field label | ||
condition | FieldCondition | Condition for showing or hiding this field | ||
sidebar | boolean | false | Place this field in the document sidebar | |
sidebarSection | string | Group under a named sidebar section | ||
listColumn | boolean | false | Show as a default column in list views | |
listColumnWidth | "auto" | "small" | "medium" | "large" | Column width preset for list views |
Example usage
import { f, defineVextroCollection } from "vextro";
export const categories = defineVextroCollection({
slug: "categories",
label: "Categories",
collectionType: "content",
tableName: "categories",
fields: {
name: f.text({ required: true }),
slug: f.slug({ sourceField: "name", required: true }),
color: f.color({
required: true,
label: "Category Color",
description: "Used for badges and highlights across the site",
listColumn: true,
listColumnWidth: "small",
}),
textColor: f.color({
label: "Text Color",
description: "Contrast color for text on the category background",
}),
},
}); Restricting formats
You can limit which formats are available to editors:
// Only hex and hsl
brandColor: f.color({ formats: ["hex", "hsl"] })
// Only hex (original behavior)
legacyColor: f.color({ formats: ["hex"] }) When only one format is provided, the format switcher is hidden.
Admin UI
The color field displays:
- A color swatch — a native color picker for quick visual selection.
- A text input — shows the current CSS color value in the active format. Editors can type any supported format directly; the format is detected automatically.
- A format switcher — segmented buttons to convert between the allowed formats. Switching format converts the current color value.
When readOnly is true, the color swatch is displayed without the picker interaction, the text input is disabled, and the format switcher is non-interactive.
Format switching behavior
Switching formats converts the current color value in place. For example, switching from hex #3b82f6 to hsl produces hsl(217, 91%, 60%). The stored value always uses the active format.
Small rounding differences may occur during conversion (especially with oklch), but the visible color remains perceptually identical.
Conditional display
backgroundColor: f.color({
label: "Background Color",
condition: { field: "useCustomColors", equals: true },
description: "Override the default section background",
})