Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f9aa1a5
Update to NHS.UK frontend v10.2.2
colinrotherham Dec 16, 2025
9ed8c60
Update text input examples
colinrotherham Dec 16, 2025
a19df04
Add text input `code` support (for codes and sequences)
colinrotherham Dec 16, 2025
13de365
Update select examples
colinrotherham Dec 16, 2025
fa7eed8
Update button examples
colinrotherham Dec 16, 2025
d4b4082
Add login button support
colinrotherham Dec 16, 2025
28159d8
Add small button support
colinrotherham Dec 16, 2025
5103d53
Simplify form group `aria-describedby` handling
colinrotherham Dec 16, 2025
96dee8e
Add support for form group `beforeInput` and `afterInput`
colinrotherham Dec 16, 2025
1699507
Add text input with button examples
colinrotherham Dec 16, 2025
992b9af
Add select with button examples
colinrotherham Dec 16, 2025
7faf768
Add password input component
colinrotherham Dec 16, 2025
cc8c5d9
Update tabs examples
colinrotherham Dec 16, 2025
7d62dc1
Update card examples
colinrotherham Dec 16, 2025
8715db7
Remove unnecessary card classes
colinrotherham Dec 16, 2025
addcd85
Add select divider support
colinrotherham Dec 16, 2025
0bd461d
Update changelog
colinrotherham Dec 16, 2025
9e23474
Update upgrade guide
colinrotherham Dec 16, 2025
504718a
Reduce duplicate button code
colinrotherham Dec 16, 2025
a2f9d13
Fix character count `undefined` hint text ID in `aria-describedby`
colinrotherham Jan 16, 2026
e64f2be
Add support for button `secondarySolid` prop
colinrotherham Jan 16, 2026
a334d5c
Add missing `role="list"` to Do and Don't list component
colinrotherham Jan 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# NHS.UK React components

## Unreleased

This version provides support for NHS.UK frontend v10.2 and includes:

- [Password input component](https://service-manual.nhs.uk/design-system/components/password-input)
- [Smaller and inline buttons](https://service-manual.nhs.uk/design-system/components/buttons#smaller-buttons)
- [Text input styles for codes and sequences](https://service-manual.nhs.uk/design-system/components/text-input#codes-and-sequences)
- [Select](https://service-manual.nhs.uk/design-system/components/select) dividers using `<Select.Divider />`

For a full list of changes in this release please refer to the [migration doc](https://github.com/NHSDigital/nhsuk-react-components/blob/main/docs/upgrade-to-6.0.md).

## 6.0.0-beta.4 - 5 November 2025

This version provides support for NHS.UK frontend v10.1 and includes:
Expand Down
66 changes: 66 additions & 0 deletions docs/upgrade-to-6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,76 @@ The updated [header](https://service-manual.nhs.uk/design-system/components/head
- update NHS logo in the header to have higher contrast when focused
- refactor CSS classes and BEM naming, use hidden attributes instead of modifier classes, use generic search element

#### Use the password input component to help users accessibly enter passwords

The [password input](https://service-manual.nhs.uk/design-system/components/password-input) component from NHS.UK frontend v10.2 allows users to choose:

- whether their passwords are visible or not
- to enter their passwords in plain text

This helps users use longer and more complex passwords without needing to remember what they've already typed.

#### Smaller versions of radio buttons and checkboxes

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.

#### Smaller versions of buttons

You can now use smaller versions of [buttons](https://service-manual.nhs.uk/design-system/components/buttons) by adding the `small` prop.

#### Secondary buttons with solid white background

By default, the secondary button is transparent and has no colour.

You can now make the [button](https://service-manual.nhs.uk/design-system/components/button) component white when you use it on darker backgrounds by adding the `secondarySolid` prop.

#### Add inline buttons to text inputs and select menus

You can now add inline buttons to text inputs and select menus using the `formGroupProps.afterInput` prop.

```jsx
<TextInput
formGroupProps={{
afterInput: () => (
<Button secondary small>
Search
</Button>
),
}},
/>
```

#### Add a 'code' prop for text inputs that accept codes and sequences

We've added a new `code` prop for the [text input](https://service-manual.nhs.uk/design-system/components/text-input) component. This improves readability of text inputs that receive codes and sequences (like NHS numbers, security codes or booking references).

```patch
<TextInput
label="What is your NHS number?"
labelProps={{ isPageHeading: true, size: 'l' }}
inputMode="numeric"
spellCheck="false"
width="10"
+ code
/>
```

#### Add a 'divider' between select options

Newer browsers support [using `<hr>` (horizontal rule) elements inside a `<select>` element](https://developer.chrome.com/blog/hr-in-select/) to help visually break up options for better readability.

We've added a new `<Select.Divider />` child component for select menus to support this feature. For example:

```patch
<Select>
<Select.Option value="first-name-ascending">First name (A to Z)</Select.Option>
<Select.Option value="first-name-descending">First name (Z to A)</Select.Option>
+ <Select.Divider />
<Select.Option value="last-name-ascending">Last name (A to Z)</Select.Option>
<Select.Option value="last-name-descending">Last name (Z to A)</Select.Option>
</Select>
```

### Numbered pagination component

The [pagination](https://service-manual.nhs.uk/design-system/components/pagination) component from NHS.UK frontend v10.1 has been updated to support numbered pagination:
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
"jest-axe": "^10.0.0",
"jest-environment-jsdom": "^30.2.0",
"lodash": "^4.17.21",
"nhsuk-frontend": "^10.1.0",
"nhsuk-frontend": "^10.2.2",
"outdent": "^0.8.0",
"prettier": "^3.7.4",
"react": "^19.2.3",
Expand All @@ -116,7 +116,7 @@
},
"peerDependencies": {
"classnames": ">=2.5.0",
"nhsuk-frontend": ">=10.1.0 <11.0.0",
"nhsuk-frontend": ">=10.2.0 <11.0.0",
"react": ">=18.2.0",
"react-dom": ">=18.2.0",
"tslib": ">=2.8.0"
Expand Down
2 changes: 2 additions & 0 deletions src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ describe('Index', () => {
'PaginationLinkText',
'Panel',
'PanelTitle',
'PasswordInput',
'Radios',
'RadiosContext',
'RadiosDivider',
Expand All @@ -110,6 +111,7 @@ describe('Index', () => {
'Row',
'SearchIcon',
'Select',
'SelectDivider',
'SelectOption',
'SkipLink',
'SummaryList',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ const DoAndDontListComponent = forwardRef<HTMLDivElement, DoAndDontListProps>(
<HeadingLevel className="nhsuk-do-dont-list__label" headingLevel={headingLevel}>
{heading || (listType === 'do' ? 'Do' : "Don't")}
</HeadingLevel>
{/* eslint-disable-next-line jsx-a11y/no-redundant-roles */}
<ul
className={classNames(
'nhsuk-list',
{ 'nhsuk-list--tick': listType === 'do' },
{ 'nhsuk-list--cross': listType === 'dont' },
)}
role="list"
>
<DoAndDontListContext.Provider value={listType}>{children}</DoAndDontListContext.Provider>
</ul>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ exports[`DoAndDontList list type "do" matches snapshot (via server): client 1`]
</h3>
<ul
class="nhsuk-list nhsuk-list--tick"
role="list"
/>
</div>
</div>
Expand All @@ -50,6 +51,7 @@ exports[`DoAndDontList list type "do" matches snapshot (via server): server 1`]
</h3>
<ul
class="nhsuk-list nhsuk-list--tick"
role="list"
/>
</div>
</div>
Expand All @@ -67,6 +69,7 @@ exports[`DoAndDontList list type "do" matches snapshot: DoDontList-Do 1`] = `
</h3>
<ul
class="nhsuk-list nhsuk-list--tick"
role="list"
/>
</div>
</div>
Expand All @@ -84,6 +87,7 @@ exports[`DoAndDontList list type "dont" matches snapshot (via server): client 1`
</h3>
<ul
class="nhsuk-list nhsuk-list--cross"
role="list"
/>
</div>
</div>
Expand All @@ -101,6 +105,7 @@ exports[`DoAndDontList list type "dont" matches snapshot (via server): server 1`
</h3>
<ul
class="nhsuk-list nhsuk-list--cross"
role="list"
/>
</div>
</div>
Expand All @@ -118,6 +123,7 @@ exports[`DoAndDontList list type "dont" matches snapshot: DoDontList-Dont 1`] =
</h3>
<ul
class="nhsuk-list nhsuk-list--cross"
role="list"
/>
</div>
</div>
Expand Down
51 changes: 30 additions & 21 deletions src/components/form-elements/button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,51 @@ import {

import { type AsElementLink } from '#util/types/LinkTypes.js';

export interface ButtonProps extends AsElementLink<HTMLButtonElement> {
export interface ButtonProps extends ButtonBaseProps, AsElementLink<HTMLButtonElement> {
href?: never;
secondary?: boolean;
reverse?: boolean;
warning?: boolean;
as?: 'button';
preventDoubleClick?: boolean;
}

export interface ButtonLinkProps extends AsElementLink<HTMLAnchorElement> {
export interface ButtonLinkProps extends ButtonBaseProps, AsElementLink<HTMLAnchorElement> {
href: string;
type?: never;
as?: 'a';
}

interface ButtonBaseProps {
secondary?: boolean;
secondarySolid?: boolean;
reverse?: boolean;
warning?: boolean;
as?: 'a';
login?: boolean;
small?: boolean;
preventDoubleClick?: boolean;
}

function getButtonClassNames(props: ButtonProps | ButtonLinkProps) {
return classNames(
'nhsuk-button',
{ 'nhsuk-button--secondary': props.secondary },
{ 'nhsuk-button--secondary-solid': props.secondarySolid },
{ 'nhsuk-button--reverse': props.reverse },
{ 'nhsuk-button--warning': props.warning },
{ 'nhsuk-button--login': props.login },
{ 'nhsuk-button--small': props.small },
props.className,
);
}

const ButtonComponent = forwardRef<HTMLButtonElement, ButtonProps>((props, forwardedRef) => {
const {
className,
asElement: Element = 'button',
disabled,
secondary,
secondarySolid,
reverse,
warning,
login,
small,
type = 'submit',
preventDoubleClick,
onClick,
Expand Down Expand Up @@ -70,13 +88,7 @@ const ButtonComponent = forwardRef<HTMLButtonElement, ButtonProps>((props, forwa

return (
<Element
className={classNames(
'nhsuk-button',
{ 'nhsuk-button--secondary': secondary },
{ 'nhsuk-button--reverse': reverse },
{ 'nhsuk-button--warning': warning },
className,
)}
className={getButtonClassNames(props)}
data-module="nhsuk-button"
data-prevent-double-click={preventDoubleClick === true ? 'true' : undefined}
disabled={disabled}
Expand All @@ -102,8 +114,11 @@ const ButtonLinkComponent = forwardRef<HTMLAnchorElement, ButtonLinkProps>(
className,
asElement: Element = 'a',
secondary,
secondarySolid,
reverse,
warning,
login,
small,
preventDoubleClick,
onClick,
...rest
Expand Down Expand Up @@ -132,13 +147,7 @@ const ButtonLinkComponent = forwardRef<HTMLAnchorElement, ButtonLinkProps>(

return (
<Element
className={classNames(
'nhsuk-button',
{ 'nhsuk-button--secondary': secondary },
{ 'nhsuk-button--reverse': reverse },
{ 'nhsuk-button--warning': warning },
className,
)}
className={getButtonClassNames(props)}
data-module="nhsuk-button"
data-prevent-double-click={preventDoubleClick === true ? 'true' : undefined}
role="button"
Expand Down
Loading