From c56a8f1d9938e91fe3ac46b5cd4a93c2b8420b9e Mon Sep 17 00:00:00 2001 From: Jeremy Ruppel Date: Tue, 30 Jun 2026 20:00:56 -0400 Subject: [PATCH] feat(site/src/pages/TemplateBuilder): add scroll overflow and sticky sidebar to wizard steps (#26881) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add vertical overflow scrolling to the TemplateBuilder wizard step content areas and make the selection sidebar sticky. ## Changes - **Scroll on inner content**: Each step's inner content area (below the heading and any tabs/search) gets `max-h-[calc(100vh-Npx)] overflow-y-auto`, keeping headings and tab bars visible while the content scrolls. - Base template select and module select grids: 420px offset (accounts for navbar, page header, card padding, tab bar, and nav controls) - Base template parameters and module settings: 340px offset - Customizations step: no scroll, flows naturally - **Sticky sidebar**: The selection summary sidebar uses `sticky top-0 self-start` to stay visible while scrolling. - **Scroll reset on navigation**: `window.scrollTo(0, 0)` in Back/Continue handlers so users start at the top of each step. > 🤖 Generated by Coder Agents
Implementation plan The approach uses `max-h` with `overflow-y-auto` on the inner content divs of each step component, placed below the step heading and any tabs/search controls. This keeps the heading fixed while the content scrolls. The offset values account for the vertical space consumed by the navbar, page header, card border/padding, and navigation controls. The `DashboardFullPage` flex-fill approach was explored but abandoned because the viewport-constrained card was too short to show content on smaller screens. The standard `Margins` + `pb-12` layout with per-step `max-h` provides a better balance.
--- .../TemplateBuilder/BaseInfraSelectStep.tsx | 3 +- .../BaseTemplateParametersStep.tsx | 49 ++++++++++--------- .../TemplateBuilder/ModuleSelectStep.tsx | 3 +- .../TemplateBuilder/ModuleSettingsStep.tsx | 3 +- .../TemplateBuilderPageView.tsx | 7 ++- 5 files changed, 38 insertions(+), 27 deletions(-) diff --git a/site/src/pages/TemplateBuilder/BaseInfraSelectStep.tsx b/site/src/pages/TemplateBuilder/BaseInfraSelectStep.tsx index 86cc4d0831..1128a0ec26 100644 --- a/site/src/pages/TemplateBuilder/BaseInfraSelectStep.tsx +++ b/site/src/pages/TemplateBuilder/BaseInfraSelectStep.tsx @@ -55,7 +55,8 @@ export const BaseInfraSelectStep: FC = ({ Select your infrastructure foundation. -
+ {/* 420px accounts for navbar, page header, card padding, tab bar, and nav controls */} +
{bases.map((base) => ( - - {prerequisites && ( -
- - {prerequisites} - -
- )} -
+ {/* 340px accounts for navbar, page header, card padding, and nav controls */} +
+ + {prerequisites && ( +
+ + {prerequisites} + +
+ )} +
+
); }; diff --git a/site/src/pages/TemplateBuilder/ModuleSelectStep.tsx b/site/src/pages/TemplateBuilder/ModuleSelectStep.tsx index d7abb8cf29..89c15434e3 100644 --- a/site/src/pages/TemplateBuilder/ModuleSelectStep.tsx +++ b/site/src/pages/TemplateBuilder/ModuleSelectStep.tsx @@ -243,7 +243,8 @@ export const ModuleSelectStep: FC = ({ -
+ {/* 420px accounts for navbar, page header, card padding, search, tabs, and nav controls */} +
{visibleModules.length ? ( visibleModules.map((m) => ( = ({ Set values for module variables. -
+ {/* 340px accounts for navbar, page header, card padding, and nav controls */} +
{selectedModules.map((mod) => { const configurableVars = mod.variables.filter((v) => !v.sensitive); const sensitiveVars = mod.variables.filter((v) => v.sensitive); diff --git a/site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx b/site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx index 73b098b6e9..099cb94a89 100644 --- a/site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx +++ b/site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx @@ -1,4 +1,5 @@ import { type FC, type ReactNode, useReducer, useState } from "react"; + import { useQuery } from "react-query"; import { templateBuilderModules } from "#/api/queries/templateBuilder"; import type { @@ -14,6 +15,7 @@ import { PageHeaderSubtitle, PageHeaderTitle, } from "#/components/PageHeader/PageHeader"; + import { docs } from "#/utils/docs"; import { BaseInfraSelectStep } from "./BaseInfraSelectStep"; import { @@ -68,6 +70,7 @@ export const TemplateBuilderPageView: FC = ({ const currentIndex = nearestVisible(stepIndex, state); const currentStep = WIZARD_STEPS[currentIndex]; + const nextIndex = findNextVisibleIndex(currentIndex, state); const prevIndex = findPrevVisibleIndex(currentIndex, state); const isFirstStep = prevIndex === -1; @@ -82,6 +85,7 @@ export const TemplateBuilderPageView: FC = ({ ); const handleBack = () => { + window.scrollTo(0, 0); setStepIndex(prevIndex); }; @@ -90,6 +94,7 @@ export const TemplateBuilderPageView: FC = ({ onCreateTemplate(state); return; } + window.scrollTo(0, 0); setStepIndex(nextIndex); }; @@ -158,7 +163,7 @@ export const TemplateBuilderPageView: FC = ({
{/* Sidebar */} -
+