Selector

Selectors are an alternative way to showcase Radio Button, Checkbox,Button or Link. They can represent a wide variety of content and it is up to the individual teams how that content inside the selectors is represented.

#Selector Link

NameTypeDefaultDescriptionControls
childrenReactNode-

The content of the link

iconReactNode-

An icon that is either placed before or after the content

-
iconPosition"before" | "after"-

Placement of the icon in relation to the content.

isDisabledboolean-

If true, the link is disabled and has no pointer events

isExternalbooleanfalse

Sets target="_blank" and rel="noreferrer"

isSelectedboolean-

If true, the link looks active/selected

minimumTargetSize"block" | "inline"-

Sets the minimal touch target size to comply with WCAG 2.2 AA standard

  • block: Adds a ::before pseudo-element to ensure a minimum target size of 40x40px (touch inputs) or 24x24px (mouse inputs) for stand-alone links (outside of text flow).
  • inline: No additional touch area is added, as inline links (within text flow) do not require expanded touch targets.

Reference: https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html#:~:text=inline%3A

prefetchboolean-

Prefetch the page in the background. Any <Link /> that is in the viewport (initially or through scroll) will be prefetched. Prefetch can be disabled by passing prefetch={false}. Prefetching is only enabled in production.

In App Router:

  • null (default): For statically generated pages, this will prefetch the full React Server Component data. For dynamic pages, this will prefetch up to the nearest route segment with a loading.js file. If there is no loading file, it will not fetch the full tree to avoid fetching too much data.
  • true: This will prefetch the full React Server Component data for all route segments, regardless of whether they contain a segment with loading.js.
  • false: This will not prefetch any data, even on hover.

In Pages Router:

  • true (default): The full route & its data will be prefetched.
  • false: Prefetching will not happen when entering the viewport, but will still happen on hover. @defaultValue true (pages router) or null (app router)
replaceboolean-

Replace the current history state instead of adding a new url into the stack. @defaultValue false

scrollboolean-

Whether to override the default scroll behavior @example https://nextjs.org/docs/api-reference/next/link#disable-scrolling-to-the-top-of-the-page @defaultValue true

shallowboolean-

Update the path of the current page without rerunning getStaticProps, getServerSideProps or getInitialProps. @defaultValue false

import { SelectorLink } from "@segments/link";

export const StatefulSelectorLink = () => {
  return <SelectorLink href="#">Text content</SelectorLink>;
};

#Selector Button

NameTypeDefaultDescriptionControls
children *ReactNode-

The content of the button

aria-labelstring-

Screenreader description of the triggered action, if not specified, tooltip will be used.

disabledboolean-

Disable the button, also sets aria-disabled to true and tabIndex to -1 @defaultValue false

isSelectedboolean-

If true, the button looks active/selected

tooltipstring-

Tooltip text describes the action of the button, appears on hover. This will be used as the aria-label if not specified explicitly.

import { SelectorButton } from "@blocks/ui";

export const StatefulSelectorButton = () => {
  const [isActive, setIsActive] = useState<boolean>(false);

  return (
    <SelectorButton
      onClick={(prevState) => setIsActive(!prevState)}
      isActive={isActive}
    >
      Text content
    </SelectorButton>
  );
};

#Selector Checkbox

NameTypeDefaultDescriptionControls
children *ReactNode-

The label of the checkbox

checkedboolean-

If true, the checkbox is checked, for controlled mode, mutually exclusive with defaultChecked

defaultCheckedboolean-

If true, the checkbox is checked initially, for uncontrolled mode, mutually exclusive with checked

disabledbooleanfalse

If true, the checkbox is disabled

hasErrorbooleanfalse

If true, the checkbox becomes outlined in red

onChangeChangeEventHandler<HTMLInputElement>-

The change event handler

-
import { SelectorCheckbox } from "@blocks/form";

export const StatefulSelectorCheckbox = () => {
  const [isChecked, setIsChecked] = useState<boolean>(false);
  return (
    <SelectorCheckbox
      checked={isChecked}
      onChange={() => setIsChecked(!isChecked)}
    >
      Text content
    </SelectorCheckbox>
  );
};

#Selector Radio Button

NameTypeDefaultDescriptionControls
children *ReactNode-

The label of the radio button

checkedboolean-

If true, the radio button is checked, mutually exclusive with defaultChecked

defaultCheckedboolean-

If true, the radio button is checked initially, for uncontrolled mode, mutually exclusive with checked

disabledbooleanfalse

If true, the radio button is disabled

hasErrorbooleanfalse

If true, the radio button becomes outlined in red

onChangeChangeEventHandler<HTMLInputElement>-

The change event handler

-
import { SelectorRadioButton } from "@blocks/form";

export const StatefulSelectorRadioButton = () => {
  const [isChecked, setIsChecked] = useState<boolean>(false);
  return (
    <SelectorRadioButton
      checked={isChecked}
      onChange={() => setIsChecked(!isChecked)}
    >
      Text content
    </SelectorRadioButton>
  );
};

#Selector Checkbox Field

A component that connects Selector Checkbox with a form and is able to show a validation message and a help text.

NameTypeDefaultDescriptionControls
children *ReactNode-

The label of the checkbox

form *UseFormReturn<TFieldValues>-

The connected form that the form field is part of

-
name *string-

The name of the input being registered from the form

-
defaultCheckedboolean-

If true, the checkbox is checked initially, for uncontrolled mode, mutually exclusive with checked

disabledboolean-

If true, the checkbox is disabled

hasErrorboolean-

If true, the checkbox becomes outlined in red

onChangeChangeEventHandler<HTMLInputElement>-

The change event handler

-
optionsPick<RegisterOptions<TFieldValues, TName>, "required" | "validate">{}

The options that can be set for the registration of the field

-
export const SelectExtras = () => {
  const form = useForm<{ extras: string[] }>();
  return (
    <form onSubmit={form.handleSubmit(() => {})}>
      <Fieldset>
        <FieldsetLegend>Which fruit are your favourite?</FieldsetLegend>
        <Flex gap="small" role="presentation">
          {fruit.map(({ label, value }) => (
            <SelectorCheckboxField
              key={value}
              form={form}
              name="fruit"
              value={value}
              defaultChecked={value === "apricot"}
              options={{ validate, required: false }}
            >
              {label}
            </SelectorCheckboxField>
          ))}
        </Flex>
        <FieldHelpText form={form} name="fruit">
          Select between one and three fruits
        </FieldHelpText>
      </Fieldset>
      <Button type="submit">Submit</Button>
    </form>
  );
};

#Validation and accessibility of checkbox lists

For accessibility reasons, the <Fieldset /> must be used, when presenting a list options with checkboxes. By providing complex functions to the validation prop, it is possible to validate the list of checkboxes in relation to the current selected opstion. The validation prop is a function that takes the value of the field and returns an error message string or true. If the function returns a string, the field is considered invalid and the string is shown as a validation message. For complex validation, refer to the demo code below.

#A list of checkboxes with validation

code
export const SelectorCheckboxFieldsDemo = () => {
  const form = useForm<{ fruit: string[] }>();

  const validate = () => {
    const values = form.getValues("fruit");
    const amount = Array.isArray(values) ? values.length : values ? 1 : 0;
    if (amount < 1) {
      return "Select at least one fruit";
    }
    if (amount > 3) {
      return "Not more than 3 fruits";
    }
    return true;
  };

  return (
    <form onSubmit={form.handleSubmit(() => {})}>
      <Fieldset>
        <FieldsetLegend>Which fruit are your favourite?</FieldsetLegend>
        <Wrapper role="presentation">
          {fruit.map(({ label, value }) => (
            <SelectorCheckboxField
              key={value}
              form={form}
              name="fruit"
              value={value}
              defaultChecked={value === "apricot"}
              options={{ validate, required: false }}
            >
              {label}
            </SelectorCheckboxField>
          ))}
        </Wrapper>
        <FieldHelpText form={form} name="fruit">
          Select between one and three fruits
        </FieldHelpText>
      </Fieldset>
      <Button type="submit">Submit</Button>
    </form>
  );
};

#Selector Radio Button Field

A component that connects Selector Radio Button with a form and is able to show a validation message and a help text.

NameTypeDefaultDescriptionControls
children *ReactNode-

The label of the checkbox

form *UseFormReturn<TFieldValues>-

The connected form that the form field is part of

-
name *string-

The name of the input being registered from the form

-
value *any-

the unique value of the radio button

-
defaultCheckedboolean-

If true, the checkbox is checked initially, for uncontrolled mode, mutually exclusive with checked

disabledboolean-

If true, the checkbox is disabled

hasErrorboolean-

If true, the checkbox becomes outlined in red

onChangeChangeEventHandler<HTMLInputElement>-

The change event handler

-
optionsPick<RegisterOptions<TFieldValues, TName>, "required">{}

The options that can be set for the registration of the field

-
export const SelectExtras = () => {
  const form = useForm<{ extras: string[] }>();
  return (
    <form onSubmit={form.handleSubmit(() => {})}>
      <Fieldset>
        <FieldsetLegend $variant="title">
          Which fruit are your favourite?
        </FieldsetLegend>
        <Flex gap="small" role="presentation">
          {fruit.map(({ label, value }) => (
            <SelectorRadioButtonField
              key={value}
              form={form}
              name="fruit"
              value={value}
              defaultChecked={value === "apricot"}
              options={{ validate, required: false }}
            >
              {label}
            </SelectorRadioButtonField>
          ))}
        </Flex>
        <FieldHelpText form={form} name="fruit">
          Select between one and three fruits
        </FieldHelpText>
      </Fieldset>
      <Button type="submit">Submit</Button>
    </form>
  );
};

#Validation and accessibility of checkbox lists

For accessibility reasons, the <Fieldset /> must be used, when presenting a list options with checkboxes. By providing complex functions to the validation prop, it is possible to validate the list of checkboxes in relation to the current selected opstion. The validation prop is a function that takes the value of the field and returns an error message string or true. If the function returns a string, the field is considered invalid and the string is shown as a validation message. For complex validation, refer to the demo code below.

#A list of radio buttons with validation

code
export const SelectorRadioButtonFieldsDemo = () => {
  const form = useForm<{ option: string }>();

  const options = {
    required: false,
  };

  return (
    <form onSubmit={form.handleSubmit(() => {})}>
      <Fieldset>
        <FieldsetLegend>Which fruit are your favourite?</FieldsetLegend>
        <Wrapper role="presentation">
          {items.map((item) => (
            <SelectorRadioButtonField
              key={item.value}
              form={form}
              name="option"
              value={item.value}
              options={options}
            >
              {item.label}
            </SelectorRadioButtonField>
          ))}
        </Wrapper>
        <FieldHelpText form={form} name="option" />
      </Fieldset>
      <Button type="submit">Submit</Button>
    </form>
  );
};

#Colors

#Selector Button

  • Token
  • BUTTON#fff#111#fff#111
  • BUTTON_ACTIVE#fff#111#fff#111
  • BUTTON_BORDER#ddd#fff4#dee#556
  • BUTTON_BORDER_ACTIVE#555#fc2#059#6bf
  • BUTTON_BORDER_ERROR#e64#f75#e02#f55
  • BUTTON_BORDER_FOCUS#07c#7cf#e02#f55
  • BUTTON_BORDER_HOVER#000#fff#e02#f55
  • BUTTON_ERROR#fff#111#fff#111
  • BUTTON_FOCUS#fff#111#fff#111
  • BUTTON_HOVER#fff#111#fff#111
  • TEXT_ERROR#f75#f75#e02#f55
  • TIME_TEXT#000#fff#059#6bf
  • TIME_TEXT_ACTIVE#000#fff#059#6bf
  • TIME_TEXT_ERROR#000#fff#059#6bf
  • TIME_TEXT_FOCUS#000#fff#e02#f55
  • TIME_TEXT_HOVER#000#fff#e02#f55

#Selector Link

  • Token
  • LINK#fff#111#fff#111
  • LINK_ACTIVE#fff#111#fff#111
  • LINK_BORDER#ddd#fff4#dee#556
  • LINK_BORDER_ACTIVE#555#fc2#059#6bf
  • LINK_BORDER_ERROR#e64#f75#e02#f55
  • LINK_BORDER_FOCUS#07c#7cf#e02#f55
  • LINK_BORDER_HOVER#000#fff#e02#f55
  • LINK_ERROR#fff#111#fff#111
  • LINK_FOCUS#fff#111#fff#111
  • LINK_HOVER#fff#111#fff#111
  • LINK_TEXT#000#fff#059#6bf
  • LINK_TEXT_ACTIVE#000#fff#059#6bf
  • LINK_TEXT_ERROR#000#fff#059#6bf
  • LINK_TEXT_FOCUS#000#fff#e02#f55
  • LINK_TEXT_HOVER#000#fff#e02#f55
  • TEXT_ERROR#f75#f75#e02#f55

#Selector Checkbox / Radio Button

  • Token
  • BOX#fff#111#fff#111
  • BOX_ACTIVE#fff#111#fff#111
  • BOX_BORDER#ddd#fff4#dee#556
  • BOX_BORDER_ACTIVE#555#fc2#059#6bf
  • BOX_BORDER_ERROR#e64#f75#e02#f55
  • BOX_BORDER_FOCUS#07c#7cf#e02#f55
  • BOX_BORDER_HOVER#000#fff#e02#f55
  • BOX_ERROR#fff#111#fff#111
  • BOX_FOCUS#fff#111#fff#111
  • BOX_HOVER#fff#111#fff#111
  • TEXT_ERROR#f75#f75#e02#f55
  • TIME_TEXT#000#fff#059#6bf
  • TIME_TEXT_ACTIVE#000#fff#059#6bf
  • TIME_TEXT_ERROR#000#fff#059#6bf
  • TIME_TEXT_FOCUS#000#fff#e02#f55
  • TIME_TEXT_HOVER#000#fff#e02#f55