Skip to content

feat: align login flow with latest Figma designs - #286

Merged
bastionstack merged 5 commits into
mainfrom
feat/login-figma-polish
Jun 15, 2026
Merged

feat: align login flow with latest Figma designs#286
bastionstack merged 5 commits into
mainfrom
feat/login-figma-polish

Conversation

@bastionstack

@bastionstack bastionstack commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements five login-flow UI changes from the external UI design Figma:

  1. Headline font now renders. font-loader injected the branding <link rel="stylesheet"> into the component's shadow root, where browsers ignore @font-face/webfont stylesheets. It now injects into document.head, so the branded heading font actually loads.
  2. Login screen: title "Howdy" → "Sign in", and the primary CTA "Continue" → "Sign in". Also adds the missing identifier.field.password label (was rendering the raw key).
  3. Sign-up screen: dropped the redundant "Enter your email to get started" subheadline (register.description is now empty by design; the template omits an empty subtitle).
  4. Skipped the post-registration passkey upsell. Passkey registration is offered up front on the register step, so the separate "Sign in faster next time?" step is removed from the default flow definition and the api-mock flow machine — registration now completes straight to done.
  5. Renamed passkey action "Register with a passkey" → "Continue with a passkey" for consistent wording.

Locale changes are mirrored across en/de/it. The "Forgot password?" control is rendered once (link only) — the duplicate secondary button was removed.

Also in this PR: api-mock logout endpoint

While verifying the flow in the demo, sign-out failed because the standalone mock auth server only served GET /sessions/me, so the SDK proxy's DELETE /__nextgen/sessions/me 404'd and left the session cookie stuck. This PR adds the spec's revokeMySession handler (DELETE /sessions/me): 204 + cookie clear on success, 401 without a cookie, 404 for an unknown session, 409 for an already-expired one. Covered by api-mock spec-conformance tests. (@zitadel/api-mock is not a published package, so no changeset.)

Changes

  • font-loader.ts — inject font <link> at document level; guard the lookup so an unrelated host-page element sharing the zl-font-link id is never clobbered (+ unit tests)
  • locales/{en,de,it}.ts — CTA/title wording, identifier.field.password, empty register.description, passkey rename
  • templates/default.liquid — omit empty subtitle; de-dupe forgot-password link
  • default-login-flow-definition.json + project_test.go — register-password → done, no passkey-upsell step
  • api-mock/flow-machine.ts + specs/AGENTS — flow goes straight to done
  • api-mock/server.ts — add DELETE /sessions/me (revokeMySession) + spec-conformance tests
  • Component/api-mock/e2e specs + dev playground updated for the no-upsell flow

Test plan

  • nx run-many -t test -p @zitadel/components,@zitadel/api-mock (components 158, api-mock 26)
  • nx run-many -t test:browser -p @zitadel/components,@zitadel/api-mock
  • nx run-many -t lint,typecheck -p @zitadel/components,@zitadel/api-mock
  • Go TestCreateProjectProvisionsDefaultLoginFlow (postgres_integration)
  • Manual browser walkthrough of demo-next: login wording + headline font load (Arimo), sign-up has no subheadline, registration completes with no passkey upsell, and sign-out now clears the session (204) and returns to /login

- Inject branding font_url at document level so branded/heading fonts render
- Login CTA "Continue" -> "Sign in"; add missing identifier.field.password label
- Drop the sign-up subheadline and the post-registration passkey upsell step
- Rename passkey registration action to "Continue with a passkey"
- Remove the duplicate "Forgot password?" button (link only)

Updates the default flow definition, api-mock flow machine, locales (en/de/it),
and the affected component/api-mock/e2e specs accordingly.

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nextgen Ready Ready Preview, Comment Jun 15, 2026 8:53am

Request Review

The standalone mock auth server only served GET /sessions/me, so the demo
sign-out (DELETE /__nextgen/sessions/me via the SDK proxy) 404'd and left
the session cookie stuck. Add the spec's revokeMySession handler: 204 +
cookie clear on success, 401 without a cookie, 404 for an unknown session,
409 for an already-expired one. Covered by spec-conformance tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
@bastionstack bastionstack changed the title feat(components): align login flow with latest Figma designs feat: align login flow with latest Figma designs Jun 15, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Aligns the <zitadel-login> orchestrator’s UI copy and flow behavior with the latest external Figma designs, including branded font loading, updated CTA/title wording, and removing the post-registration passkey upsell from the default flow. It also updates the api-mock and related test suites to match the new “register → done” behavior.

Changes:

  • Load branding.font_url via a document-level <link rel="stylesheet"> (instead of inside the Shadow DOM) and adjust the default Liquid template to omit empty subtitles and de-duplicate forgot-password rendering.
  • Update en/de/it locales for “Sign in” CTAs, add the missing identifier.field.password label, remove the sign-up subtitle, and rename the passkey registration action to “Continue with a passkey”.
  • Remove the post-registration passkey-upsell step from the default flow definition and route api-mock flows directly to done, updating unit/e2e specs and dev playground docs accordingly (plus adding api-mock logout coverage).

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/components/src/orchestrator/zitadel-login.spec.ts Updates component spec helper/expectations for the no-upsell flow completion.
packages/components/src/orchestrator/templates/default.liquid Omits empty subtitles and renders forgot-password only once using the recover action metadata.
packages/components/src/orchestrator/locales/en.ts Updates sign-in wording, adds password label key, empties register subtitle, renames passkey CTA.
packages/components/src/orchestrator/locales/de.ts Mirrors the en locale changes for German.
packages/components/src/orchestrator/locales/it.ts Mirrors the en locale changes for Italian.
packages/components/src/orchestrator/font-loader.ts Moves font stylesheet injection to document.head and cleans up legacy shadow-root insertion.
packages/components/dev/pages/login.ts Updates dev playground guidance/examples to reflect “sign-in → done” (no upsell).
packages/api-mock/src/spec-conformance.spec.ts Adds conformance coverage for DELETE /sessions/me behavior (revoke + cookie clear).
packages/api-mock/src/server.ts Adds DELETE /sessions/me logout endpoint and documents it in the custom routes list.
packages/api-mock/src/index.spec.ts Updates MSW handler tests for the no-upsell register/login paths and adjusts passkey login scenario setup.
packages/api-mock/src/index.browser.spec.ts Updates browser MSW test to go straight from submit to done.
packages/api-mock/src/flow-machine.ts Changes default transitions to route login/register submits directly to done while keeping legacy upsell states reachable via injection.
packages/api-mock/AGENTS.md Updates documented happy path and clarifies legacy upsell fixtures are now injection-only.
internal/api/integration_test/project_test.go Updates integration test to assert the default flow no longer contains the passkey-upsell step.
apps/demo-nuxt-e2e/src/auth.spec.ts Removes passkey-upsell interaction from Nuxt e2e sign-in and tightens URL wait timeout.
apps/demo-next/src/app/login/widget.tsx Removes the “Howdy!” locale override so the widget uses the default “Sign in” title/copy.
apps/demo-next-e2e/src/auth.spec.ts Removes passkey-upsell interaction from Next e2e sign-in and tightens URL wait timeout.
apps/cli-journey-e2e/src/user-journey.spec.ts Updates CLI journey registration helper to reflect registration completing directly (no upsell).
api/openapi/endpoints/flow_definitions/examples/default-login-flow-definition.json Removes passkey-upsell from the default flow example by targeting done after register-password submit.
.changeset/login-figma-polish.md Adds a patch changeset for @zitadel/components describing the user-visible login-flow adjustments.

Comment thread packages/components/src/orchestrator/font-loader.ts Outdated
Comment thread packages/api-mock/src/server.ts
Address PR review: applyFontUrl cast getElementById() to HTMLLinkElement and
removed it, which could clobber an unrelated host-page element sharing the
"zl-font-link" id. Only treat a matching stylesheet <link> we own as existing.
Adds font-loader unit coverage for inject/idempotent/replace/remove and the
no-clobber guard.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop the defensive instanceof/getElementById guard in favour of a
tag-scoped `link#zl-font-link` lookup, which by construction only matches
our own <link> (no risk of clobbering an unrelated host node). Reuse the
existing link across re-renders and only update href when it changes,
avoiding a needless font re-fetch on every render. Trim the tests to the
inject / reuse / remove behaviours.

Co-authored-by: Cursor <cursoragent@cursor.com>
@bastionstack
bastionstack enabled auto-merge (squash) June 15, 2026 08:54
@bastionstack
bastionstack merged commit 3795b67 into main Jun 15, 2026
13 checks passed
@bastionstack
bastionstack deleted the feat/login-figma-polish branch June 15, 2026 08:54
vitorbari added a commit that referenced this pull request Jun 15, 2026
Resolves conflicts with #286 (login Figma polish):
- default-login example JSON: dropped passkey-upsell step (removed on main)
- packages/components default.liquid: kept new array iteration; threaded
  main's actions_by_name.recover forgot-link guard and the `recover`
  exclusion in the secondary-action loop
- project_test.go: switched the FindStep("passkey-upsell") assertion to
  the main-side `assert.False(t, ok)` form

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fforootd pushed a commit that referenced this pull request Jun 15, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`main` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `main`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @zitadel/cli@0.1.0-alpha.5

### Minor Changes

- [#257](#257)
[`6f8dd2d`](6f8dd2d)
Thanks [@mridang](https://github.com/mridang)! - Add `setup --framework
react|vue|angular|nuxt` support to the CLI. Each framework scaffolds its
auth entry/pages and wires `/__nextgen/*` calls to the backend with a
`sk_<project_id>` bearer attached: React and Vue get a dev proxy
magicast-merged into the Vite config (`vite.config.*`) that reads the
project id from `ZITADEL_PROJECT_ID`; Angular gets a `proxy.conf.cjs`
wired into `angular.json` that reads it from `zitadel.json`; and Nuxt
registers the `@zitadel/sdk-nuxt` module in the Nuxt config
(`nuxt.config.*`), which adds the proxy via server middleware. A
`--dev-port` flag sets the scaffolded dev-server port.

- [#299](#299)
[`f77ca44`](f77ca44)
Thanks [@fforootd](https://github.com/fforootd)! - Make the generated
Next.js auth app easier for agents and developers to prove end-to-end
registration, logout, and login in a visible browser.

### Patch Changes

- [#295](#295)
[`f02718f`](f02718f)
Thanks [@fforootd](https://github.com/fforootd)! - Allow fresh app
scaffolding after `zitadel start` creates local runtime ignore files,
and load Nuxt runtime config through the Nuxt virtual imports module.

- Updated dependencies []:
  - @zitadel/api@0.1.0-alpha.5
## @zitadel/components@0.1.0-alpha.5

### Patch Changes

- [#299](#299)
[`f77ca44`](f77ca44)
Thanks [@fforootd](https://github.com/fforootd)! - Make the generated
Next.js auth app easier for agents and developers to prove end-to-end
registration, logout, and login in a visible browser.

- [#286](#286)
[`3795b67`](3795b67)
Thanks [@bastionstack](https://github.com/bastionstack)! - Align the
login flow with the latest Figma designs: load `branding.font_url` at
document level so branded fonts (including the heading face) actually
render, change the sign-in CTA from "Continue" to "Sign in", add the
missing `identifier.field.password` label, drop the sign-up subheadline,
and rename the passkey registration action to "Continue with a passkey".
The default login flow no longer shows the post-registration passkey
upsell screen — passkey registration is offered up front instead.
## @zitadel/sdk-angular@0.1.0-alpha.5

### Patch Changes

- Updated dependencies
[[`f77ca44`](f77ca44),
[`3795b67`](3795b67)]:
  - @zitadel/components@0.1.0-alpha.5
  - @zitadel/api@0.1.0-alpha.5
## @zitadel/sdk-next@0.1.0-alpha.5

### Patch Changes

- Updated dependencies
[[`f77ca44`](f77ca44),
[`3795b67`](3795b67)]:
  - @zitadel/components@0.1.0-alpha.5
  - @zitadel/api@0.1.0-alpha.5
  - @zitadel/sdk-core@0.1.0-alpha.5
## @zitadel/sdk-nuxt@0.1.0-alpha.5

### Patch Changes

- [#295](#295)
[`f02718f`](f02718f)
Thanks [@fforootd](https://github.com/fforootd)! - Allow fresh app
scaffolding after `zitadel start` creates local runtime ignore files,
and load Nuxt runtime config through the Nuxt virtual imports module.

- Updated dependencies
[[`f77ca44`](f77ca44),
[`3795b67`](3795b67)]:
  - @zitadel/components@0.1.0-alpha.5
  - @zitadel/api@0.1.0-alpha.5
  - @zitadel/sdk-core@0.1.0-alpha.5
## @zitadel/sdk-react@0.1.0-alpha.5

### Patch Changes

- Updated dependencies
[[`f77ca44`](f77ca44),
[`3795b67`](3795b67)]:
  - @zitadel/components@0.1.0-alpha.5
  - @zitadel/api@0.1.0-alpha.5
  - @zitadel/sdk-core@0.1.0-alpha.5
## @zitadel/sdk-vue@0.1.0-alpha.5

### Patch Changes

- Updated dependencies
[[`f77ca44`](f77ca44),
[`3795b67`](3795b67)]:
  - @zitadel/components@0.1.0-alpha.5
  - @zitadel/api@0.1.0-alpha.5
  - @zitadel/sdk-core@0.1.0-alpha.5
## @zitadel/api@0.1.0-alpha.5


## @zitadel/sdk-core@0.1.0-alpha.5

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants