Skip to contentAsheeUIAsheeUI

AuthLayout

The shell of an authentication route, a measured form column, a panel to draw it on, a heading, and an optional media column beside it.

An authentication route is one form and very little else, so the page around it is mostly a decision about where the form sits. AuthLayout supplies that: the column is centred in the height it is given, it keeps a readable measure, it can be drawn on a panel, and it has somewhere to put the brand, the heading, the supporting sentence and the link to the other route.

It carries no authentication of its own. There is no field registry, no validation and no request: the form is children, and everything the reader submits is the page's.

Reach for it when the whole screen is a way in, sign in, sign up, reset, verify. For a screen behind that door, the shell is SidebarLayout or Page.

Usage

import {
  AuthLayout,
  Form,
  Input,
  Link,
  PasswordInput,
  VStack,
} from "@asheeui/web";

<AuthLayout
  brand="Ashee SMS"
  title="Sign in"
  description="Use the email address your workspace knows."
  footer={<Link href="/sign-up">Create an account</Link>}
>
  <Form aria-label="Sign in" submitLabel="Sign in" onSubmit={signIn}>
    <VStack gap="md">
      <Input label="Email" type="email" name="email" autoComplete="email" />
      <PasswordInput label="Password" name="password" />
    </VStack>
  </Form>
</AuthLayout>;

That is the whole contract. brand, title and description fill the block above the form, children is the form, and footer is the row under it. The shell decides where those sit; the page decides what they say, every field, the submit control and the form's own name included.

The media column

media is a slot rather than a picture prop: pass a screenshot, a card of numbers, a quotation, whatever the page wants beside the form. With content in it the shell becomes two columns from the lg breakpoint (1024 pixels), the media taking half of the width, and mediaPosition states which half.

Below lg there is only one column, so the media stacks in the order the side puts it in the flow: above the form for start, below it for the registered end. That is deliberate, a product shot under a short form still reads as part of the page, while a figure above a long form would push the first field past the fold.

The panel and the measure

Three options decide what the form is drawn on and how wide it is. panel (registered true) wraps the form in a bordered surface with its own padding; without it the form sits directly on the page background. align (registered center) centres the column vertically, or holds it at the top for a route with a long form or a message above it. contentSize (registered sm) is the maximum width of that column, taken from the width tokens.

The three are independent on purpose: a sign-up route usually wants panel={false}, align="start" and a wider measure, and stating one of them should not quietly change the others.

Props

All four layout options are registered by the component, so each resolves from the instance, then from components.authlayout, then from the registration: panel true, align center, mediaPosition end, contentSize sm. brand, title, description, children, footer and media are instance-only, because they are the page's own words, and as is instance-only too. There is no colour or variant option: the panel is the framework's own bordered surface, so it follows the theme's border and background rather than asking the page. Its corners are not a layout option either, the radius resolves from the application's defaultRadius, with md as the hard fallback when no configuration supplies one, so a product that rounds every surface rounds the sign-in panel with them.

Accessibility

  • The shell renders no landmark. It is a div unless as says otherwise, so place it inside the document's main, or pass as="main" when the shell is the route's whole page.
  • title renders an <h2>, not the page's <h1>. It goes through the shared section heading at the lg step, and that heading renders an <h2> at every size by default; this layout has no titleAs to raise it, because a layout that decided the page's top-level heading for it would be deciding the route's outline. So a route that states its own <h1>, a line of the brand, or a heading at the top of children, keeps title as the section heading beneath it, and a route whose title is the page's only heading states that <h1> itself rather than expecting the shell to render one.
  • The form is yours, including its name. The shell renders no form element and adds no aria-label, so the name and the submit control come from the Form you pass (its legend, or its aria-label).
  • panel and the media column are visual boundaries only: neither is a landmark, a region or a name, and alternative text belongs to the media you pass into the slot.

The tokens behind contentSize and the gaps inside the form are the ones Layout and spacing describes; which shell a product should start from is the argument in Page compositions.

Native

@asheeui/native ships AuthLayout with the same props and the same cascade. The platform's differences are the platform's: the shell fills the screen the platform gives it rather than claiming a viewport height, nothing scrolls, and the media column is placed from the same lg width by the platform's own measurement instead of by a media query. See React Native.