npm package: @highlight-ui/radio-button
Description: This is the Radio Button package used in Personio
Author: Personio GmbH & Co. KG
Latest version: 5.1.15

[![npm](https://img.shields.io/npm/v/@highlight-ui/radio-button)](https://www.npmjs.com/package/@highlight-ui/radio-button)
[![personio.design](https://img.shields.io/static/v1?label=Personio&message=zeroheight&color=yellow)](https://www.personio.design/40d648a47/p/043999-radio-button/b/26fe12)
[![storybook.personio.design](https://img.shields.io/static/v1?label=Personio&message=storybook&color=red)](https://storybook.personio.design/?path=/story/forms-and-input-radiobutton-radiobutton--basic-radio-button)

# @highlight-ui/radio-button

A control that allows the user to toggle between checked and unchecked states. Used to pick one option from a set of multiple available options. If you require a multi-selection input, please use the [Checkbox](https://www.npmjs.com/package/@highlight-ui/checkbox).

## Features

- RadioButton
  - Controlled component
  - Optional label to display next to the RadioButton input
  - Optional sub-label to display under the main label
  - Optional tooltip placed next to the main input label
- RadioButtonGroup
  - Renders multiple RadioButtons given array of options
  - Controlled component
  - Vertical or horizontal display
  - Optional name to apply to all RadioButtons within the group

## Installation

Using npm:

```bash
npm install @highlight-ui/radio-button
```

Using yarn:

```bash
yarn add @highlight-ui/radio-button
```

Using pnpm:

```bash
pnpm install @highlight-ui/radio-button
```

In your (S)CSS file:

```scss
@import url('@highlight-ui/radio-button');
```

Once the package is installed, you can import the library:

```tsx
import { RadioButton, RadioButtonGroup } from '@highlight-ui/radio-button';
```

## Usage

### RadioButton

```tsx
import React, { useState } from 'react';
import { RadioButton } from '@highlight-ui/radio-button';

export default function RadioButtonExample() {
  const [checkedStatus, setCheckedStatus] = useState(false);

  return (
    <RadioButton
      id="radio-button"
      label="Click me to toggle me"
      subLabel="I am only a radio button input"
      checked={checkedStatus}
      onClick={() => setCheckedStatus(!checkedStatus)}
    />
  );
}
```

### RadioButtonGroup

```tsx
import React, { useState } from 'react';
import { RadioButtonGroup } from '@highlight-ui/radio-button';

export default function RadioButtonGroupExample() {
  const [checked, setChecked] = useState<string | number | undefined>(
    undefined,
  );
  const options = [
    { value: 'option-a', label: 'Option A', subLabel: 'Most important' },
    { value: 'option-b', label: 'Option B', subLabel: 'Average' },
    { value: 'option-c', label: 'Option C', subLabel: 'Lowest priority' },
  ];

  return (
    <RadioButtonGroup
      name="RadioButton-group"
      orientation="horizontal"
      options={options}
      value={checked}
      onChange={(option) => setChecked(option.value)}
    />
  );
}
```

## Props 📜

### RadioButton

> All `HTMLInputElement` and [PropsWithMetadata(https://gitlab.personio-internal.de/personio/platform/highlight-ui/-/blob/master/packages/utils/commons/src/types.ts#L24)] props are accepted with this component. In addition to these, this component has the following props

| Prop                   | Type                                        | Required | Default   | Description                                                                                                                                                                                                                                                                     |
| :--------------------- | :------------------------------------------ | :------- | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `label`                | `string`                                    | No       | `null`    | Text displayed next to the radio button input                                                                                                                                                                                                                                   |
| `subLabel`             | `string`                                    | No       | `null`    | Text displayed below the main label                                                                                                                                                                                                                                             |
| `tooltipContent`       | `React.ReactNode`                           | No       | `null`    | The content of the tooltip pop-out. When supplied, a tooltip will be placed next to the label. This maps to the [TooltipProps['content']](https://gitlab.personio-internal.de/personio/platform/highlight-ui/-/blob/master/packages/ui/tooltip/src/Tooltip.tsx#L21) prop types. |
| `tooltipMouseOutDelay` | `'none'`, `'medium'`, `'long'`, or `number` | No       | `null`    | Specifies how to to keep the tooltip opened after the mouse has left the tooltip icon. This maps to the [TooltipProps['mouseOutDelay']](https://gitlab.personio-internal.de/personio/platform/highlight-ui/-/blob/master/packages/ui/tooltip/src/Tooltip.tsx#L14) prop types.   |
| `tone`                 | `default` or `error`                        | No       | `default` | Sets the tone of the radio button                                                                                                                                                                                                                                               |

### RadioButtonGroup

Note that the `RadioButtonGroupOption` type matches the `RadioButton` listed properties above.

| Prop          | Type                                             | Required | Default    | Description                                                  |
| :------------ | :----------------------------------------------- | :------- | :--------- | :----------------------------------------------------------- |
| `value`       | `RadioButtonGroupOption['value']`                | Yes      |            | Currently checked value                                      |
| `onChange`    | `function(option: RadioButtonGroupOption): void` | Yes      |            | Function called when the checked status of an option changes |
| `orientation` | `vertical` or `horizontal`                       | No       | `vertical` | Display of the radio button group                            |
| `options`     | `RadioButtonGroupOption[]`                       | Yes      |            | Options to render as a group                                 |

## Accessibility ♿️

Following [base accesibility guidelines](https://www.magentaa11y.com/checklist-web/radio/), the radio-button input currently:

- Allows clicking radio button input and main label to check or uncheck
- Associates the radio button input with its label through the `for` prop referring to the `id`

Potential future improvements to make it more accessible:

- Adding focus on the whole radio button and label container
- Including `aria` tags to indicate checked and disabled states
- Tooltip accessibility will be addressed in a future release as it is currently not adequate

## Testing

There are a number of unit tests covering the `RadioButton` and `RadioButtonGroup` components, the snippets below can serve as a base to expand future testing if new behaviours are added.

The relevant render methods provide the option to add or override prop values.

### RadioButton

```tsx
import React from 'react';
import { render } from '@testing-library/react';
import { RadioButton, RadioButtonProps } from '@highlight-ui/radio-button';

type Optional<T, K extends keyof T> = Omit<T, K> & Partial<T>;
type RadioButtonWrapperProps = Optional<
  RadioButtonProps,
  'checked' | 'onClick'
>;

function RadioButtonWrapper(props: RadioButtonWrapperProps) {
  const [checked, setChecked] = useState(false);

  return (
    <RadioButton
      checked={checked}
      onClick={() => setChecked(!checked)}
      {...props}
    />
  );
}

describe('RadioButtonTest', () => {
  const renderRadioButtonWrapper = (props: RadioButtonWrapperProps) => {
    return render(<RadioButtonWrapper {...props} />);
  };

  it('test description', () => {
    renderRadioButtonWrapper({});
    // write your expect here
  });
});
```

### RadioButtonGroup

```tsx
import React from 'react';
import { render } from '@testing-library/react';

import { RadioButtonGroup, RadioButtonGroupProps, RadioButtonGroupOption }  from '@highlight-ui/radio-button';

type Optional<T, K extends keyof T> = Omit<T, K> & Partial<T>;
type RadioButtonGroupWrapperProps = Optional<
  RadioButtonGroupProps,
  'value' | 'onChange' | 'options'
>;

function RadioButtonGroupWrapper(props: RadioButtonGroupWrapperProps) {
  const [checked, setChecked] = useState<string | number | undefined>(
    undefined,
  );
  const options = [
    { value: 'option-a', label: 'Option A', subLabel: 'Most important' },
    { value: 'option-b', label: 'Option B', subLabel: 'Average' },
    { value: 'option-c', label: 'Option C', subLabel: 'Lowest priority' },
  ];

  return (
    <RadioButtonGroup
      name="RadioButton-group"
      options={options}
      value={checked}
      onChange={(option) => setChecked(option.value)}
      {...props}
    />
  );
}

describe('RadioButtonGroupTest', () => {
  const renderRadioButtonGroupWrapper = (props: RadioButtonGroupWrapperProps) => {
    return render(<RadioButtonWrapper {...props} />);
  };

  it('test description', () => {
    renderRadioButtonGroupWrapper({});
    // write your expect here
  });
};
```

## Place in design system 💻

The radio button and radio button group are components currently unused in other components and packages.

## Contributing 🖌️

Please visit [personio.design](https://www.personio.design/40d648a47/v/0/p/043999-radio-button/b/26fe12) for usage guidelines and visual examples.

If you're interested in contributing, please visit our [contribution page](https://www.personio.design/40d648a47/v/0/p/138faf-about-the-process).