Skip to content

Commit 97f19db

Browse files
Add smaller versions of radio buttons and checkboxes (#289)
* Update data attributes to use string values * Allow unused vars as object rest siblings * Fix missing character count max length * Update to NHS.UK frontend v10.1.0 * Add support for small radios and checkboxes * Add small form control examples * Update upgrade guide
1 parent f707dbc commit 97f19db

File tree

14 files changed

+120
-37
lines changed

14 files changed

+120
-37
lines changed

docs/upgrade-to-6.0.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ The updated [header](https://service-manual.nhs.uk/design-system/components/head
1818
- update NHS logo in the header to have higher contrast when focused
1919
- refactor CSS classes and BEM naming, use hidden attributes instead of modifier classes, use generic search element
2020

21+
#### Smaller versions of radio buttons and checkboxes
22+
23+
You can now use smaller versions of the [radios](https://service-manual.nhs.uk/design-system/components/radios) and [checkboxes](https://service-manual.nhs.uk/design-system/components/checkboxes) components by adding the `small` prop.
24+
2125
### Panel component
2226

2327
The [panel](https://service-manual.nhs.uk/design-system/components/panel) component from NHS.UK frontend v9.3.0 has been added:

eslint.config.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@ export default defineConfig([
4343
'import/no-named-as-default-member': 'off',
4444
'import/no-unresolved': 'off',
4545
'import/no-unused-modules': 'off',
46+
47+
// Prefer rules that are type aware
48+
'no-unused-vars': 'off',
49+
'@typescript-eslint/no-unused-vars': [
50+
'error',
51+
{
52+
argsIgnorePattern: '^_',
53+
varsIgnorePattern: '^_',
54+
ignoreRestSiblings: true,
55+
},
56+
],
4657
},
4758
settings: {
4859
'import/resolver': {

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@
107107
"jest-axe": "^10.0.0",
108108
"jest-environment-jsdom": "^30.2.0",
109109
"lodash": "^4.17.21",
110-
"nhsuk-frontend": "^10.0.0",
110+
"nhsuk-frontend": "^10.1.0",
111111
"outdent": "^0.8.0",
112112
"prettier": "^3.6.2",
113113
"react": "^19.2.0",
@@ -124,7 +124,7 @@
124124
},
125125
"peerDependencies": {
126126
"classnames": ">=2.5.0",
127-
"nhsuk-frontend": ">=10.0.0 <11.0.0",
127+
"nhsuk-frontend": ">=10.1.0 <11.0.0",
128128
"react": ">=18.2.0",
129129
"react-dom": ">=18.2.0",
130130
"tslib": ">=2.8.0"

src/components/form-elements/character-count/CharacterCount.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ export const CharacterCount = forwardRef<HTMLTextAreaElement, CharacterCountProp
4141
...formGroupProps,
4242
'className': classNames('nhsuk-character-count', formGroupProps?.className),
4343
'data-module': 'nhsuk-character-count',
44-
'data-maxlength': maxLength,
45-
'data-maxwords': maxWords,
46-
'data-threshold': threshold,
44+
'data-maxlength': maxLength?.toString(),
45+
'data-maxwords': maxWords?.toString(),
46+
'data-threshold': threshold?.toString(),
4747
'ref': moduleRef,
4848
}}
4949
{...rest}

src/components/form-elements/character-count/__tests__/CharacterCount.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('Character Count', () => {
5050
const fieldRef = createRef<HTMLTextAreaElement>();
5151

5252
const { container } = await renderClient(
53-
<CharacterCount formGroupProps={{ ref: groupRef }} ref={fieldRef} />,
53+
<CharacterCount formGroupProps={{ ref: groupRef }} ref={fieldRef} maxLength={200} />,
5454
{ moduleName: 'nhsuk-character-count' },
5555
);
5656

src/components/form-elements/checkboxes/Checkboxes.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface CheckboxesProps
1313
extends ComponentPropsWithoutRef<'div'>,
1414
Omit<FormElementProps, 'label' | 'labelProps'> {
1515
idPrefix?: string;
16+
small?: boolean;
1617
}
1718

1819
const CheckboxesComponent = forwardRef<HTMLDivElement, CheckboxesProps>((props, forwardedRef) => {
@@ -71,8 +72,7 @@ const CheckboxesComponent = forwardRef<HTMLDivElement, CheckboxesProps>((props,
7172

7273
return (
7374
<FormGroup<CheckboxesProps> inputType="checkboxes" {...rest}>
74-
{/* eslint-disable-next-line @typescript-eslint/no-unused-vars */}
75-
{({ className, name, id, idPrefix, error, ...restRenderProps }) => {
75+
{({ className, small, name, id, idPrefix, error, ...restRenderProps }) => {
7676
resetCheckboxIds();
7777
const contextValue: ICheckboxesContext = {
7878
name,
@@ -82,7 +82,11 @@ const CheckboxesComponent = forwardRef<HTMLDivElement, CheckboxesProps>((props,
8282
};
8383
return (
8484
<div
85-
className={classNames('nhsuk-checkboxes', className)}
85+
className={classNames(
86+
'nhsuk-checkboxes',
87+
{ 'nhsuk-checkboxes--small': small },
88+
className,
89+
)}
8690
data-module="nhsuk-checkboxes"
8791
id={id}
8892
ref={moduleRef}

src/components/form-elements/checkboxes/components/CheckboxesItem.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
import { CheckboxesContext, type ICheckboxesContext } from '../CheckboxesContext.js';
1414
import { HintText } from '#components/form-elements/hint-text/index.js';
1515
import { Label } from '#components/form-elements/label/index.js';
16-
import { type FormElementProps, type HTMLAttributesWithData } from '#util/types/index.js';
16+
import { type ComponentPropsWithDataAttributes, type FormElementProps } from '#util/types/index.js';
1717

1818
export interface CheckboxesItemProps
1919
extends ComponentPropsWithoutRef<'input'>,
@@ -54,10 +54,10 @@ export const CheckboxesItem = forwardRef<HTMLInputElement, CheckboxesItemProps>(
5454

5555
useEffect(() => () => unleaseReference(checkboxReference));
5656

57-
const inputProps: HTMLAttributesWithData<HTMLInputElement> = rest;
57+
const inputProps: ComponentPropsWithDataAttributes<'input'> = rest;
5858

5959
if (exclusive) {
60-
inputProps['data-checkbox-exclusive'] = true;
60+
inputProps['data-checkbox-exclusive'] = 'true';
6161
}
6262

6363
return (

src/components/form-elements/radios/Radios.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import { type FormElementProps } from '#util/types/FormTypes.js';
1212
export interface RadiosProps
1313
extends ComponentPropsWithoutRef<'div'>,
1414
Omit<FormElementProps, 'label' | 'labelProps'> {
15-
inline?: boolean;
1615
idPrefix?: string;
16+
inline?: boolean;
17+
small?: boolean;
1718
}
1819

1920
const RadiosComponent = forwardRef<HTMLDivElement, RadiosProps>((props, forwardedRef) => {
@@ -78,8 +79,7 @@ const RadiosComponent = forwardRef<HTMLDivElement, RadiosProps>((props, forwarde
7879

7980
return (
8081
<FormGroup<RadiosProps> inputType="radios" {...rest}>
81-
{/* eslint-disable-next-line @typescript-eslint/no-unused-vars */}
82-
{({ className, inline, name, id, error, ...restRenderProps }) => {
82+
{({ className, inline, small, name, id, error, ...restRenderProps }) => {
8383
resetRadioIds();
8484
const contextValue: IRadiosContext = {
8585
getRadioId: (reference) => getRadioId(id, reference),
@@ -92,7 +92,14 @@ const RadiosComponent = forwardRef<HTMLDivElement, RadiosProps>((props, forwarde
9292

9393
return (
9494
<div
95-
className={classNames('nhsuk-radios', { 'nhsuk-radios--inline': inline }, className)}
95+
className={classNames(
96+
'nhsuk-radios',
97+
{
98+
'nhsuk-radios--inline': inline,
99+
'nhsuk-radios--small': small,
100+
},
101+
className,
102+
)}
96103
data-module="nhsuk-radios"
97104
id={id}
98105
ref={moduleRef}

src/components/utils/__tests__/FormGroup.test.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,6 @@ describe('FormGroup', () => {
220220
it('string component', async () => {
221221
const { container } = await renderClient(
222222
<FormGroup<TextInputProps> inputType="input" error="Oh no there's an error!">
223-
{/* eslint-disable-next-line @typescript-eslint/no-unused-vars */}
224223
{({ error, ...rest }) => <input {...rest} />}
225224
</FormGroup>,
226225
{ className: 'nhsuk-form-group' },
@@ -245,7 +244,6 @@ describe('FormGroup', () => {
245244
hint="This is a hint"
246245
label="Form Label"
247246
>
248-
{/* eslint-disable-next-line @typescript-eslint/no-unused-vars */}
249247
{({ error, ...rest }) => <input {...rest} />}
250248
</FormGroup>
251249
</main>,
@@ -264,7 +262,6 @@ describe('FormGroup', () => {
264262
error="This is an error"
265263
hint="This is a hint"
266264
>
267-
{/* eslint-disable-next-line @typescript-eslint/no-unused-vars */}
268265
{({ error, ...rest }) => <input {...rest} />}
269266
</FormGroup>,
270267
{ className: 'nhsuk-form-group' },
@@ -279,7 +276,6 @@ describe('FormGroup', () => {
279276
it('should have no aria-describedby when there is no hint or label', async () => {
280277
const { container } = await renderClient(
281278
<FormGroup<TextInputProps> inputType="input">
282-
{/* eslint-disable-next-line @typescript-eslint/no-unused-vars */}
283279
{({ error, ...rest }) => <input {...rest} />}
284280
</FormGroup>,
285281
{ className: 'nhsuk-form-group' },

src/util/types/FormTypes.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import { type ComponentPropsWithRef } from 'react';
2-
31
import { type ErrorMessageProps } from '#components/form-elements/error-message/index.js';
42
import { type FieldsetProps } from '#components/form-elements/fieldset/index.js';
53
import { type HintTextProps } from '#components/form-elements/hint-text/index.js';
64
import { type LabelProps } from '#components/form-elements/label/index.js';
75
import { type LegendProps } from '#components/form-elements/legend/index.js';
6+
import { type ComponentPropsWithDataAttributes } from '#util/types/NHSUKTypes.js';
87

98
export interface FormElementProps {
109
'fieldsetProps'?: FieldsetProps;
@@ -16,12 +15,7 @@ export interface FormElementProps {
1615
'errorProps'?: ErrorMessageProps;
1716
'hint'?: string;
1817
'hintProps'?: HintTextProps;
19-
'formGroupProps'?: ComponentPropsWithRef<'div'> & {
20-
'data-module'?: string;
21-
'data-maxlength'?: number;
22-
'data-maxwords'?: number;
23-
'data-threshold'?: number;
24-
};
18+
'formGroupProps'?: ComponentPropsWithDataAttributes<'div'>;
2519
'id'?: string;
2620
'name'?: string;
2721
'aria-describedby'?: string;

0 commit comments

Comments
 (0)