Skip to content
CodeAtlas UI

Layout

AppForm

A page-level form layout with a fixed header, a scrollable body and a sticky footer.

<script>
  import { AppForm, FormSection, TextField, Button } from "@codeatlasdev/ui";
</script>

<AppForm title="New user" backHref="/users">
  <FormSection title="Account">
    <TextField label="Name" bind:value={name} />
  </FormSection>
  {#snippet footer()}
    <Button variant="ghost" href="/users">Cancel</Button>
    <Button variant="filled" onclick={save}>Save</Button>
  {/snippet}
</AppForm>

AppForm fills its parent, so give the parent a height. It replaces the removed FormPage. For a floating action bar inside your own scroll container, use StickyActions.

Basic form

Header with a back button, a grid of fields, a list of switches and a sticky footer.

New User

Fill in the details to create a new user.

Account details

Basic information for the new user.

Notifications

Email preferences.

Code
svelte
<script lang="ts">
  import { AppForm, FormSection, TextField, Select, Switch, Button, Divider } from '@codeatlasdev/ui';
  import { ArrowLeft } from '@lucide/svelte';

  let name = $state('');
  let email = $state('');
  let role = $state('viewer');
  let welcome = $state(true);
  let digest = $state(false);
  let saving = $state(false);

  function save() {
    saving = true;
    setTimeout(() => (saving = false), 1400);
  }

  const roleOptions = [
    { value: 'admin', label: 'Admin' },
    { value: 'editor', label: 'Editor' },
    { value: 'viewer', label: 'Viewer' },
  ];
</script>

<div class="frame">
  <AppForm title="New User" description="Fill in the details to create a new user.">
    {#snippet leading()}
      <Button variant="ghost" size="sm" aria-label="Back">
        {#snippet leading()}<ArrowLeft size={15} />{/snippet}
      </Button>
    {/snippet}

    <FormSection title="Account details" description="Basic information for the new user.">
      <TextField label="Full name" bind:value={name} placeholder="Ada Lovelace" />
      <TextField label="Work email" bind:value={email} placeholder="ada@company.com" type="email" />
      <Select label="Role" bind:value={role} options={roleOptions} />
    </FormSection>

    <FormSection title="Notifications" description="Email preferences." layout="list">
      <Switch label="Send welcome email" bind:checked={welcome} />
      <Divider />
      <Switch label="Weekly digest" bind:checked={digest} />
    </FormSection>

    {#snippet footer()}
      <Button variant="ghost">Cancel</Button>
      <Button variant="filled" onclick={save} disabled={saving || !name || !email}>
        {saving ? 'Saving…' : 'Create user'}
      </Button>
    {/snippet}
  </AppForm>
</div>

<style>
  .frame {
    width: 100%;
    height: 480px;
    border-radius: var(--ca-radius-lg);
    box-shadow: inset 0 0 0 1px var(--ca-outline-subtle);
    overflow: hidden;
    display: flex;
    flex-direction: column;
  }
</style>

Without header

Omit title, description, leading, trailing and backHref to drop the header.

Quick update
Code
svelte
<script lang="ts">
  import { AppForm, FormSection, TextField, Button } from '@codeatlasdev/ui';
</script>

<div class="frame">
  <AppForm>
    <FormSection title="Quick update">
      <TextField label="Name" placeholder="Enter name…" />
      <TextField label="Email" type="email" placeholder="email@example.com" />
    </FormSection>
    {#snippet footer()}
      <Button variant="ghost">Cancel</Button>
      <Button variant="filled">Save</Button>
    {/snippet}
  </AppForm>
</div>

<style>
  .frame {
    width: 100%;
    height: 360px;
    border-radius: var(--ca-radius-lg);
    box-shadow: inset 0 0 0 1px var(--ca-outline-subtle);
    overflow: hidden;
    display: flex;
    flex-direction: column;
  }
</style>

Props

PropTypeDefaultDescription
titlestring–Page title in the header.
descriptionstring–Subtitle under the title.
backHrefstring–Renders a back-arrow button linking here. Ignored when leading is provided.
backLabelstring'Back'Accessible label of the automatic back button.
leadingSnippet–Left side of the header, such as a back button or breadcrumb. Overrides backHref.
trailingSnippet–Right side of the header, such as a status chip or secondary actions.
footerSnippet–Sticky bottom bar for cancel, save and delete buttons.
childrenSnippet–Form body. Usually FormSection components.
classstring''Extra class names.