Skip to content

Conversation

@MatMoore
Copy link
Contributor

@MatMoore MatMoore commented Jan 28, 2026

Description

This brings in a version of the stepper component as app-stepper-input, and wires it up to the customised IntegerField in the nhsforms app.

Example usage:

            stepper_field = IntegerField(
                label="Stepper",
                initial=1,
                min_value=0,
                max_value=10,
                widget=StepperInput,  # this is new
            )

At the time of writing, the additional image details form is not merged yet, but I can update that to use this component when it is.

Note: I've added a little debug page at /debug/components in order to preview components like this that are not coming from the design system. This is not enabled in the review environments as I don't intend to be visible except for developers running in DEBUG mode. If you prefer, I can remove this page, but I found useful for manual testing.

Example rendering of the component

Jira link

https://nhsd-jira.digital.nhs.uk/browse/DTOSS-12115

Review notes

  • I've based the javascript, html and scss on @colinrotherham's proposal from [WIP] Add stepper input component nhsuk/nhsuk-frontend#1719
  • I've kept the aria attributes, and hiding the buttons when javascript is not available
  • I've removed some of the extra params we won't be using straight away, to simplify things
  • I tweaked one of the polyfills slightly to match the behaviour I saw in chrome, and tested it again on safari for iOS

Post merge tasks

  • contribute unit tests back to @colinrotherham's PR against nhsuk-frontend
  • raise a separate PR for propagating label.id from input to label in nhsuk-frontend

Review checklist

  • Check database queries are correctly scoped to current_provider

@MatMoore MatMoore changed the title stepper component [wip] stepper component Jan 28, 2026
@MatMoore MatMoore force-pushed the DTOSS-12115-stepper-component branch from 5109562 to 6f1f116 Compare January 28, 2026 17:14
@MatMoore MatMoore force-pushed the DTOSS-12115-stepper-component branch from 6f1f116 to 707124a Compare January 29, 2026 08:58
@github-actions
Copy link

The review app is available at this URL:
https://pr-955.manage-breast-screening.non-live.screening.nhs.uk
You must authenticate with HTTP basic authentication. Ask the team for credentials.

@MatMoore MatMoore force-pushed the DTOSS-12115-stepper-component branch from 707124a to fd4995b Compare January 29, 2026 10:30
@MatMoore MatMoore force-pushed the DTOSS-12115-stepper-component branch from fd4995b to 2d0bd7a Compare January 29, 2026 10:33
@MatMoore MatMoore force-pushed the DTOSS-12115-stepper-component branch from 2d0bd7a to cd6d31c Compare January 29, 2026 15:19
@MatMoore MatMoore changed the title [wip] stepper component Stepper component for use on the additional images form Jan 29, 2026
@MatMoore MatMoore changed the title Stepper component for use on the additional images form Stepper component for use on the additional image details form Jan 29, 2026

// Polyfill default value on step up
if (isEmpty && event?.currentTarget === this.$buttonStepUp) {
$input.valueAsNumber = min === 0 ? 1 : min
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the polyfill I changed. If the input is blank and min is 0, step up sets it to 1, not 0.


beforeEach(async () => {
document.body.innerHTML = `
<div class="nhsuk-form-group app-stepper-input" data-module="app-stepper-input" data-max="20" data-min="0">
Copy link
Contributor Author

@MatMoore MatMoore Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's awkward having to specify all this HTML here... for the nhsuk-frontend version, we can just render the nunjucks macro. I considered bringing in nunjucks as a dependency and rendering the jinja component as if it was nunjucks, but I thought this would complicate things too much.

expect(liveRegion.innerText).toBe('2')
})

it('assumes the min value when stepping down if the input is empty', async () => {
Copy link
Contributor Author

@MatMoore MatMoore Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: these two tests are technically testing jsdom, as this behaviour is normally provided by a browser, but I thought it was worth including as it helps to document the intended behaviour.

.nhsuk-form-group .app-button--link {
display: block;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This scss is all unchanged from the nhsuk-frontend PR, excpept I've renamed the class prefixes to app-

@@ -0,0 +1,40 @@
{#
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might become obsolete soon if the icons are accepted into the design system, but I copied the macro structure as I thought it would be handy to have. If we need another custom SVG at any point we can just add it here.

This allows timeouts to cause a redirect to the persona login in local
dev.
This repurposes Colin's proposed code for the design system.
See nhsuk/nhsuk-frontend#1719

I've stripped out a few options that we don't need right now
in order to focus on the use case we have.

Should this be accepted into the design system, we'll back out these
changes, but the way we call the component will be very similar.
This extends our existing version of IntegerField so that it renders
with a stepper when the StepperInput widget is specified.
@MatMoore MatMoore force-pushed the DTOSS-12115-stepper-component branch from bc8c847 to 97dd7a2 Compare January 29, 2026 16:43
@MatMoore MatMoore marked this pull request as ready for review January 29, 2026 16:44
@sonarqubecloud
Copy link


def test_renders_stepper_input(self, form_class):
actual = form_class()["stepper_field"].as_field_group()
expected = render_to_string(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured out I could render the underlying component like this to simplify the test. This means the test is not sensitive to the implementation of the jinja component, only that we pass through the right params from the field to the component.

We should do this for the other fields too but I didn't want to overload this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant