Once UI Handbook
Beginner Guides
What is Once UI?
Install & config
Page skeleton
Your first page
Build And Launch
How to launch a portfolio site that actually gets you hired
How to build a documentation site with MDX and Next.js
How to ship a landing page and dashboard with authentication in Next.js
How to launch a social app with Next.js and Supabase
Vibe Coding
Introduction to vibe coding
Set up your local dev environment
Essential tools for vibe coding
Build your first Once UI app
Common Patterns
Hero section
Static panel
Form layout
Highlighted card
Responsive stacking
Decoration layers
Dialog & modal
Toast & feedback
Tables & lists
Loading states
App shell navigation
Dashboard & charts
Chat & messaging
Auth & verification
Settings & split panels
Data filters & toolbar
Command palette
Pricing & plans
Accordion & FAQ
Media & uploads
Empty & error states
SEO, Open Graph, and structured data
Documentation code blocks with live preview
Carousels, galleries, and before/after comparisons
Date pickers and scheduling
Context menus and dropdown actions
Tags, chips, and multi-value inputs
Roadmap & kanban
Form inputs & controls
Progress, status & badges
Scrolling & feeds
Profile, avatars & identity
Social proof & logo clouds
Masonry & media grids
Table pagination, search & bulk selection
Banners & announcements
Footer layouts
Onboarding & first run
Waitlist & coming soon
Design Tips
Color & surfaces
Harness overview
Row, Column & Grid
Spacing & rhythm
Icons & buttons
Reveal & motion
Theme tokens, FOUC-free init, and runtime style controls
Tooltips and hover cards
Block updates
Block updates changelog
Agent Resources
Column, not Flex
Semantics over CSS
Typography scale
Common gotchas
Block anchors
Validate generated code
Pro block registry
Match task bundles
TrademarkTrademark
Ctrl k
Search...
Sign up
Once UI Handbook
Beginner Guides
What is Once UI?
Install & config
Page skeleton
Your first page
Build And Launch
How to launch a portfolio site that actually gets you hired
How to build a documentation site with MDX and Next.js
How to ship a landing page and dashboard with authentication in Next.js
How to launch a social app with Next.js and Supabase
Vibe Coding
Introduction to vibe coding
Set up your local dev environment
Essential tools for vibe coding
Build your first Once UI app
Common Patterns
Hero section
Static panel
Form layout
Highlighted card
Responsive stacking
Decoration layers
Dialog & modal
Toast & feedback
Tables & lists
Loading states
App shell navigation
Dashboard & charts
Chat & messaging
Auth & verification
Settings & split panels
Data filters & toolbar
Command palette
Pricing & plans
Accordion & FAQ
Media & uploads
Empty & error states
SEO, Open Graph, and structured data
Documentation code blocks with live preview
Carousels, galleries, and before/after comparisons
Date pickers and scheduling
Context menus and dropdown actions
Tags, chips, and multi-value inputs
Roadmap & kanban
Form inputs & controls
Progress, status & badges
Scrolling & feeds
Profile, avatars & identity
Social proof & logo clouds
Masonry & media grids
Table pagination, search & bulk selection
Banners & announcements
Footer layouts
Onboarding & first run
Waitlist & coming soon
Design Tips
Color & surfaces
Harness overview
Row, Column & Grid
Spacing & rhythm
Icons & buttons
Reveal & motion
Theme tokens, FOUC-free init, and runtime style controls
Tooltips and hover cards
Block updates
Block updates changelog
Agent Resources
Column, not Flex
Semantics over CSS
Typography scale
Common gotchas
Block anchors
Validate generated code
Pro block registry
Match task bundles
TrademarkTrademark
Once UIDocumentationBlog
© Once UI. All rights reserved.
Built with Aveiro

Auth & verification

Split sign-up layouts, social auth, PasswordInput, and OTP verification in stacked dialogs.
Updated 19d ago
Chat & messaging
Settings & split panels
6 min · Pattern
Auth flows combine split layouts, social sign-in, email/password fields, and stacked dialogs for OTP verification. Once UI ships PasswordInput and OTPInput for the sensitive steps.

What this pattern covers

Production auth is rarely a single form. Typical flows include:
  • Split hero + form layout for sign-up and login
  • Social auth buttons above an email divider
  • Password fields with visibility toggle
  • OTP verification in a stacked dialog after email submit
Gold reference: packages/core/ai/examples/auth.tsx and task bundle packages/core/ai/tasks/auth.json.

Split layout

Use a two-column Grid that collapses to one column on mobile:
<Column as="main" fillWidth center padding="24" minHeight="100vh">
  <Grid
    fillWidth
    maxWidth="l"
    columns="2"
    radius="xl"
    border="neutral-alpha-weak"
    overflow="hidden"
    background="surface"
    s={{ columns: 1 }}
  >
    <Column minHeight={40} s={{ hide: true }}>
      {/* Media hero — hidden on mobile */}
    </Column>
    <Column padding="48" gap="32" center>
      {/* Form column */}
    </Column>
  </Grid>
</Column>
Hide the media column on small screens with s={{ hide: true }}. Keep the form column full-width and centered.

Social auth + divider

Stack social buttons first, then a horizontal divider:
<Column fillWidth gap="12">
  <Button fillWidth>Continue with GitHub</Button>
  <Button fillWidth variant="secondary">Continue with Google</Button>
</Column>

<Row fillWidth vertical="center" gap="16">
  <Line fill />
  <Text variant="label-default-s" onBackground="neutral-weak">or</Text>
  <Line fill />
</Row>
Use variant="secondary" for the alternate provider so the primary OAuth option stands out.

Email and password fields

Use Input for email and PasswordInput for passwords — it includes a built-in visibility toggle and label support.
<Column fillWidth gap="16">
  <Input id="email" label="Email" placeholder="you@company.com" />
  <Row fillWidth horizontal="end">
    <SmartLink href="/forgot">Forgot password?</SmartLink>
  </Row>
  <Button fillWidth arrowIcon>Sign up</Button>
</Column>
Reference PasswordInput in prose: pass id, label, and placeholder the same way as Input. Never use a plain Input with type="password" — PasswordInput handles the toggle affordance.

OTP verification dialog

After the user submits their email, open a with OTPInput inside:
stacked Dialog
  • Base page stays visible under the overlay
  • Dialog title explains the step ("Check your email")
  • OTPInput receives a 6-digit code
  • Footer holds Resend (secondary) and Verify (primary)
Use the stack prop on the OTP dialog if another dialog is already open (e.g. a terms acceptance step). See Dialog & modal for stacked dialog mechanics.
OTPInput props: length (default 6), onComplete callback when all digits are entered, and standard id / label.

Write this / not this

✅ Once UI way
❌ Common mistake
Grid `columns="2"` with `s={{ columns: 1 }}`Flexbox with manual breakpoints
PasswordInput for passwords`<Input type="password">`
OTP in stacked DialogInline OTP on the same page after redirect
`Line` + Text divider between social and emailCustom `<hr>` with inline styles
SmartLink for "Sign in" / "Forgot password"Raw `<a>` tags

Check yourself

  • Hero column hidden on mobile (s={{ hide: true }})
  • Social buttons use fillWidth
  • PasswordInput (not plain Input) for password fields
  • OTP step uses Dialog with footer actions
  • Destructive account actions are on a separate settings page, not in auth

Related

→ Dialog & modal → Form layout → Settings & split panels → Full reference: docs.once-ui.com — PasswordInput