Merge pull request #30458 from stephenglass/patch/scaffolder-scroll-to-top

fix(scaffolder): Scroll to top when navigating template form steps
This commit is contained in:
Ben Lambert
2025-07-08 11:35:22 +02:00
committed by GitHub
3 changed files with 47 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-react': patch
---
Scroll to the top of the page when navigating between steps in template forms.
@@ -672,6 +672,40 @@ describe('Stepper', () => {
);
});
it('should scroll the first main element to top when activeStep changes', async () => {
const manifest: TemplateParameterSchema = {
steps: [
{ title: 'Step 1', schema: { properties: {} } },
{ title: 'Step 2', schema: { properties: {} } },
],
title: 'Scroll Test',
};
// Render a main element in the document for the Stepper to find
const main = document.createElement('main');
document.body.appendChild(main);
const scrollToMock = jest.fn();
main.scrollTo = scrollToMock;
// Render Stepper as usual (do not pass container)
const { getByRole, unmount } = await renderInTestApp(
<SecretsContextProvider>
<Stepper manifest={manifest} extensions={[]} onCreate={jest.fn()} />
</SecretsContextProvider>,
);
// Click next to change the activeStep
await act(async () => {
fireEvent.click(getByRole('button', { name: 'Next' }));
});
expect(scrollToMock).toHaveBeenCalledWith({ top: 0, behavior: 'auto' });
// Clean up
document.body.removeChild(main);
unmount();
});
describe('Scaffolder Layouts', () => {
it('should render the step in the scaffolder layout', async () => {
const ScaffolderLayout: LayoutTemplate = ({ properties }) => (
@@ -37,6 +37,7 @@ import { merge } from 'lodash';
import {
ComponentType,
useCallback,
useEffect,
useMemo,
useState,
type ReactNode,
@@ -218,6 +219,13 @@ export const Stepper = (stepperProps: StepperProps) => {
[validation, analytics],
);
useEffect(() => {
const main = document.querySelector('main');
if (main && typeof main.scrollTo === 'function') {
main.scrollTo({ top: 0, behavior: 'auto' });
}
}, [activeStep]);
const mergedUiSchema = merge({}, propUiSchema, currentStep?.uiSchema);
const [isCreating, setIsCreating] = useState(false);