alpha

useColorField

Provides the behavior and accessibility implementation for a color field component. Color fields allow users to enter and adjust a hex color value.

installyarn add @react-aria/color
version3.0.0-alpha.0
usageimport {useColorField} from '@react-aria/color'

API#


useColorField( props: AriaColorFieldProps, state: ColorFieldState, ref: RefObject<HTMLInputElement> ): ColorFieldAria

Features#


The <input type="color"> HTML element can be used to build a color picker, however it is very inconsistent across browsers and operating systems and consists of a complete color picker rather than a single field for editing a hex value. useColorField helps achieve accessible color fields that can be styled as needed.

  • Support for parsing and formatting a hex color value
  • Validates keyboard entry as the user types so that only valid hex characters are accepted
  • Supports using the arrow keys to increment and decrement the value
  • Support for customizing the step value for incrementing and decrementing
  • Exposed to assistive technology as a textbox via ARIA
  • Visual and ARIA labeling support
  • Follows the spinbutton ARIA pattern
  • Works around bugs in VoiceOver with the spinbutton role
  • Uses an ARIA live region to ensure that value changes are announced

Anatomy#


Color field anatomy diagram#ABCDEFBackground colorInputLabel

A color field consists of an input element and a label. useColorField automatically manages the relationship between the two elements using the for attribute on the <label> element and the aria-labelledby attribute on the <input> element.

useColorField returns two sets of props that you should spread onto the appropriate element:

NameTypeDescription
labelPropsLabelHTMLAttributes<HTMLLabelElement>
inputPropsHTMLAttributes<HTMLInputElement>

State is managed by the useColorFieldState hook from @react-stately/color. The state object should be passed as an option to useColorField

If there is no visual label, an aria-label or aria-labelledby prop must be passed instead to identify the element to screen readers.

Example#


import {useColorFieldState} from '@react-stately/color';

function ColorField(props) {
  let state = useColorFieldState(props);
  let inputRef = React.useRef();
  let {labelProps, inputProps} = useColorField(props, state, inputRef);

  return (
    <div style={{display: 'inline-flex', flexDirection: 'column'}}>
      <label {...labelProps}>{props.label}</label>
      <input {...inputProps} ref={inputRef} />
    </div>
  );
}

<ColorField label="Color" />
import {useColorFieldState} from '@react-stately/color';

function ColorField(props) {
  let state = useColorFieldState(props);
  let inputRef = React.useRef();
  let {labelProps, inputProps} = useColorField(
    props,
    state,
    inputRef
  );

  return (
    <div
      style={{
        display: 'inline-flex',
        flexDirection: 'column'
      }}>
      <label {...labelProps}>{props.label}</label>
      <input {...inputProps} ref={inputRef} />
    </div>
  );
}

<ColorField label="Color" />
import {useColorFieldState} from '@react-stately/color';

function ColorField(
  props
) {
  let state = useColorFieldState(
    props
  );
  let inputRef = React.useRef();
  let {
    labelProps,
    inputProps
  } = useColorField(
    props,
    state,
    inputRef
  );

  return (
    <div
      style={{
        display:
          'inline-flex',
        flexDirection:
          'column'
      }}>
      <label
        {...labelProps}>
        {props.label}
      </label>
      <input
        {...inputProps}
        ref={inputRef}
      />
    </div>
  );
}

<ColorField label="Color" />

Usage#


The following examples show how to use the ColorField component created in the above example.

Uncontrolled#

By default, ColorField is uncontrolled. You can set a default value using the defaultValue prop.

<ColorField defaultValue="#7f007f" />
<ColorField defaultValue="#7f007f" />
<ColorField defaultValue="#7f007f" />

Controlled#

A ColorField can be made controlled. The parseColor function is used to parse the initial color from a hex string, stored in state. The value and onChange props are used to update the value in state when the edits the value.

import {parseColor} from '@react-stately/color';

function Example() {
  let [color, setColor] = React.useState(parseColor('#7f007f'));
  return (
    <>
      <ColorField value={color} onChange={setColor} />
      <p>Current color value: {color.toString('hex')}</p>
    </>
  );
}
import {parseColor} from '@react-stately/color';

function Example() {
  let [color, setColor] = React.useState(
    parseColor('#7f007f')
  );
  return (
    <>
      <ColorField value={color} onChange={setColor} />
      <p>Current color value: {color.toString('hex')}</p>
    </>
  );
}
import {parseColor} from '@react-stately/color';

function Example() {
  let [
    color,
    setColor
  ] = React.useState(
    parseColor('#7f007f')
  );
  return (
    <>
      <ColorField
        value={color}
        onChange={
          setColor
        }
      />
      <p>
        Current color
        value:{' '}
        {color.toString(
          'hex'
        )}
      </p>
    </>
  );
}

Step#

The step prop can be used to make a ColorField snap its value to specific increments.

<ColorField defaultValue="#7f007f" step={16} />
<ColorField defaultValue="#7f007f" step={16} />
<ColorField
  defaultValue="#7f007f"
  step={16}
/>

Disabled and read only#

A ColorField can be disabled using the isDisabled prop, and made read only using the isReadOnly prop. The difference is that read only color fields are focusable but disabled color fields are not.

<ColorField defaultValue="#7f007f" isDisabled />
<ColorField defaultValue="#7f007f" isReadOnly />
<ColorField defaultValue="#7f007f" isDisabled />
<ColorField defaultValue="#7f007f" isReadOnly />
<ColorField
  defaultValue="#7f007f"
  isDisabled
/>
<ColorField
  defaultValue="#7f007f"
  isReadOnly
/>

Internationalization#


RTL#

In right-to-left languages, color fields should be mirrored. The label should be right aligned, along with the text in the input. Ensure that your CSS accounts for this.