feat(templates): add the vertical wizard page template - #5672
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
xinzi-bot
left a comment
There was a problem hiding this comment.
Thanks—the responsive rail and guidance hierarchy are thoughtful. Two interaction gaps remain: leaving a broken step backward can hide it from later validation, and errors for Categories, Territories, or Agreements have no focus target, so blocked Continue leaves keyboard users at the footer. Please make every navigation path preserve validation and move focus to each failed field.
[Automated review]
cixzhang
left a comment
There was a problem hiding this comment.
xinzi-bot already caught the hidden-step and missing-focus paths; this confirms both and adds completion and responsive-host failures. This flow still isn’t safe to copy yet. People can bypass an invalid step, reach Submit, and get no completion; Cancel, Save and exit, and Enter are inert. When Categories, Territories, or Agreements are the only errors, Continue leaves focus on itself, so keyboard users must hunt for the field.
The three-column layout keys to viewport width. In a 700px host inside a wide page, it keeps the rail and guidance panel and crushes the form to 100px.
Could we make every exit path real, validate the whole wizard before completion, focus the first invalid field, and switch modes from available width? The final review should use provider-aware date and price formatting and the Wizard category so typechecking passes.
[Reviewed by Robohands]
This is not a functional app. This is just a template to demonstrate layout
A five-step audiobook publishing flow. The differentiator against the other wizards in the family is that the steps live in a rail beside the form rather than above it, which suits steps that are long or unequal in size: the rail stays legible at five entries with descriptions, and the form beside it can run past a screenful without the progress scrolling away. The rail's counterpart is a guidance panel on the other side. It carries a summary of the current step until a field takes focus, then swaps to what that field affects. Deliberately not a live region — the panel changes on every focus move, and announcing it each time would talk over the field's own label on every tab stop. It is a labelled landmark instead, so it can be reached on demand, and its text says what a field affects rather than repeating the hint already attached to the field. Space is given up in stages rather than all at once. Guidance is the first to go, since it is the only panel whose content is also reachable from the fields themselves. The rail goes next, rotating into a horizontal stepper above the form so progress survives the loss of the column. A blocked Continue sends focus to the first field that needs attention, the same behaviour as the horizontal wizard, so the footer never carries a second copy of a message the field is already showing. Co-authored-by: Cursor <cursoragent@cursor.com>
…type `type="label"` is not a HeadingType — the prop only carries the display scale, which sizes a heading up rather than down. The lookup missed, so no size style was applied at all and the heading inherited whatever ambient size it landed next to. It looked right by accident and broke the docsite type check. Level 5 with accessibilityLevel 2 says it properly: label-sized, but level 2 in the outline, because the panel sits beside the step rather than under it. Co-authored-by: Cursor <cursoragent@cursor.com>
The cover was five hand-written declarations — width, aspect ratio, object fit, radius, border — for an image the system already has components for. Card takes a width and draws the border and radius, and clips to it; AspectRatio takes the ratio and the object fit. Both now come from props, and the swap also picks up the radius token rather than naming it. The 640px measure was another three, and they were a verbatim copy of what Layout's own contentWidth emits. That prop applies them to the middle row, which here holds the rail and the guidance panel as well as the form, so it would cap all three columns together. Center plus Stack's maxWidth says the same thing about the one box that should be capped. That left a real defect visible. The footer spans the page and centred on it, which only matches the form when the panels are symmetric. In the middle tier — rail up, guidance gone — the buttons sat 142px left of the fields they submit. They now lean with the column, and the measured offset is 0 at every width across both breakpoints. Cover art swapped to illustrative-vertical-1. Co-authored-by: Cursor <cursoragent@cursor.com>
6863053 to
45124a7
Compare
PR Analysis Report
Generated by PR Enrichment workflow | View current CI run |
The template declares category 'Form - Wizard Vertical', which was missing from the TemplateCategory union, failing the template-docs typecheck.
Fifth of the wizard family. Stacked on #5659 for the Stepper's one-line label truncation; siblings #5660 and #5664 sit alongside it.
What differentiates it
The steps live in a rail beside the form rather than above it. That suits steps that are long or unequal in size: the rail stays legible at five entries carrying descriptions, and the form beside it can run past a screenful without the progress scrolling away.
The rail's counterpart is a guidance panel on the other side, holding a summary of the current step until a field takes focus, then swapping to what that field affects:
It is deliberately not a live region. The panel changes on every focus move, and announcing it each time would talk over the field's own label and description on every tab stop. It is a labelled landmark instead, so a screen reader user can reach it on demand — which is also why the text says what a field affects rather than repeating the hint already attached to the field.
Giving up space in stages
Guidance goes first, at 1320px, since it is the only panel whose content is also reachable from the fields themselves:
The rail goes at 1000px, rotating into a horizontal stepper above the form so progress survives the loss of the column:
The last step reviews everything as an icon-led metadata list:
A blocked Continue sends focus to the first field needing attention, the same behaviour as #5664, so the footer never carries a second copy of a message the field is already showing:
Audit
92/100, grade A, under template rubric 1.3.
The first audit came in at 85 on ten custom declarations, and the cover image was carrying most of them. Three rounds of that turned out to be the system's own job:
width,aspectRatio,objectFit,borderRadiusandborderwritten by hand.Cardtakes a width and draws the border and radius — and clips to it — whileAspectRatiotakes the ratio and the object fit. Five declarations to zero, and the radius now comes from the token rather than being named.width: 100%/maxWidth/marginInline: auto, which is character-for-character whatLayout'scontentWidthemits. That prop applies them to the middle row, which here holds the rail and the guidance panel as well as the form, so it would cap all three columns together instead of the one that should be capped.CenterplusStack'smaxWidthsays the same thing about the right box. Three to zero.Three declarations remain, each without a prop to use instead: a zero flex basis so the dropzone column can shrink, a height so the dropzone ends level with the cover (
FileInputexposeswidthbut notheight), and the footer lean described below.The 5 points still on purity are the single
<img>— the rubric's own listed exception, since there is no Image component and thesrcis a checked-in/template-assets/path.A defect the refactor exposed
Reworking the measure made it visible that the footer spans the page and centred on the page, which only matches the form when the panels are symmetric. With both up or both down it was fine, but in the middle tier — rail up, guidance gone — the buttons sat 142px left of the fields they submit. That was there before this refactor; it just was not obvious until the two boxes were expressed the same way.
The footer now leans with the column. Measured footer-to-form centre offset is 0px at 1440, 1360, 1319, 1200, 1100, 1010, 999, 900, 760 and 520 — both sides of both breakpoints.
Three other declarations came out during the first audit rather than being defended:
position: stickyon the guidance panel was a no-op, confirmed by measuring (the form scrolls 478px while the panel heading holds at 81px, because the panel is its own layout cell and never scrolls), andminWidth: 0duplicated a resetStackItemalready applies.template.doc.mjsalso had a stale sentence claiming the rail collapses to a counter, which the staged responsive work had replaced.Test plan
tscclean against the docsite projectOne follow-up commit early on: the guidance heading carried
type="label", which is not aHeadingType— the prop only holds the display scale, so it sizes a heading up. The lookup missed, no size style applied, and it inherited whatever ambient size it sat next to. It looked right by accident and only surfaced in the docsite type check, since Vite's dev server does not typecheck. Nowlevel={5} accessibilityLevel={2}: label-sized, level 2 in the outline.Made with Cursor