ColorField
A colour field is the one colour control you type into. It is where a reader who already knows the value goes — pasting a hex from a brand guide — rather than hunting for it on a ColorArea or a ColorSlider.
import { ColorField, ColorInputGroup, ColorInputGroupInput, ColorInputGroupPrefix } from "ropav";ColorInputGroup is the bordered box, ColorInputGroupInput the text input inside it, and ColorInputGroupPrefix and ColorInputGroupSuffix hold whatever sits at either end — a ColorSwatch showing the value is the usual one.
<ColorField class="w-72" default-value="#0485f7">
<Label>Brand colour</Label>
<ColorInputGroup>
<ColorInputGroupPrefix>
<ColorSwatch />
</ColorInputGroupPrefix>
<ColorInputGroupInput />
</ColorInputGroup>
</ColorField>Hex or a channel
Without a channel the field edits the whole colour as a hex value. Give it one and the field edits that channel as a number instead, with the stepper keys a number field has.
color-field-channel.vue
<script setup lang="ts">
import {
ColorField,
ColorInputGroup,
ColorInputGroupInput,
ColorInputGroupPrefix,
ColorSwatch,
Label,
} from "ropav";
</script>
<template>
<div class="stack">
<ColorField default-value="#0485f7">
<Label>Hex</Label>
<ColorInputGroup>
<ColorInputGroupPrefix><ColorSwatch size="xs" /></ColorInputGroupPrefix>
<ColorInputGroupInput />
</ColorInputGroup>
</ColorField>
<ColorField channel="red" color-space="rgb" default-value="#0485f7">
<Label>Red</Label>
<ColorInputGroup>
<ColorInputGroupInput />
</ColorInputGroup>
</ColorField>
</div>
</template>
<style scoped>
.stack {
display: flex;
width: 100%;
max-width: var(--rp-container-xs);
flex-direction: column;
gap: calc(var(--rp-spacing) * 4);
}
</style>These are two different controls, not one control configured two ways: they have their own state, their own keyboard and their own DOM, so changing channel at runtime rebuilds the field. Decide which one a field is and leave it there.
That split reaches validation too. is-invalid and validate are read on the hex branch only — a channel field's validity is the number field's underneath, which is built without either.
Accessibility
- The
idlands on the input, because the input is the field as far as assistive technology is concerned. ALabelpointing at the field reaches it. - The text being typed and the colour it parses to are held apart until the value is committed, so a half-typed
#04is not announced as an invalid colour while the reader is still in the middle of it. - A swatch in the prefix is decoration — the value is already in the input, and announcing it twice is worse than not announcing it at all.
API
| Prop | Type | Default | Description |
|---|---|---|---|
ariaDescribedby | string | — | |
ariaLabel | string | — | |
ariaLabelledby | string | — | |
autoFocus | boolean | — | |
channel | "alpha" | "blue" | "brightness" | "green" | "hue" | "lightness" | "red" | "saturation" | — | The channel the field edits. Without one the field edits the colour as a hex value, which is a different control: the two branches have their own state, their own keyboard and their own DOM, and changing this at runtime rebuilds the field rather than reconfiguring it. |
colorSpace | "hsb" | "hsl" | "rgb" | — | The colour space the field works in when a channel is given. Ignored without one — a hex field always shows the colour as an RGB hex value. |
defaultValue | string | Color | null | — | Colour the field starts with, and goes back to when the form is reset. |
form | string | — | Id of the form the field belongs to, when it is not nested inside one. |
fullWidth | boolean | — | Whether the field stretches to fill its container. Declared as a plain boolean rather than through the variants type: the SFC compiler cannot resolve an imported indexed-access type into a runtime prop type, and without type: Boolean Vue never casts a valueless attribute — <ColorField full-width> would arrive as "" and read as falsy, so the modifier would silently never apply. |
id | string | — | Lands on the input, which is the field as far as assistive technology is concerned. |
isDisabled | boolean | — | |
isInvalid | boolean | — | Controlled validity. Present at all — true *or* false — pins the field. Only read on the hex branch. A channel field ignores it, along with validate, exactly as React does: its validation state is the number field's, which is built without either. |
isReadOnly | boolean | — | |
isRequired | boolean | — | |
isWheelDisabled | boolean | — | Whether the wheel over a focused field is ignored. |
name | string | — | Name the field submits under. |
validate | ValidationFunction<Color | null> | — | Only read on the hex branch. |
validationBehavior | "aria" | "native" | — | |
value | string | Color | null | — | Controlled colour. A string is parsed; one that will not parse is treated as absent. |
The default slot receives:
| Slot prop | Type |
|---|---|
channel | "hex" | ColorChannel |
colorValue | Color | null |
isDisabled | boolean |
isInvalid | boolean |
isReadOnly | boolean |
isRequired | boolean |
validationDetails | ValidationDetails |
validationErrors | string[] |
| Event | Payload |
|---|---|
change | Color | null |
focusChange | boolean |
update:value | Color | null |
The parts around the input come from ColorInputGroup, which a ColorPicker reuses.
ColorInputGroup
| Prop | Type | Default | Description |
|---|---|---|---|
fullWidth | boolean | — | Whether the group stretches to fill its container. |
isDisabled | boolean | — | Whether the group reads as disabled. Taken from the surrounding field when unset, which is how the field's own disabled state reaches the shell around the control. |
isInvalid | boolean | — | Whether the group reads as invalid. Taken from the surrounding field when unset. |
size | "xs" | "sm" | "md" | "lg" | "md" | How tall the group stands, matching a button of the same size. |
variant | "primary" | "secondary" | "primary" | Visual variant. |
The default slot receives:
| Slot prop | Type |
|---|---|
isDisabled | boolean |
isFocusVisible | boolean |
isFocusWithin | boolean |
isHovered | boolean |
isInvalid | boolean |
ColorInputGroupInput
| Prop | Type | Default | Description |
|---|---|---|---|
placeholder | string | — | Placeholder shown while the control is empty. Declared so it can also be set here rather than only on the field; every other native attribute arrives by attribute fallthrough. |
ColorInputGroupPrefix
Slots: default.
ColorInputGroupSuffix
Slots: default.