Layout & navigation

AppFormSection

The form-page skeleton — titled sections, a responsive field grid, and an action bar.

<app-form-section> · <app-form-row> · <app-form-actions>

Three small layout helpers so every settings/profile/billing form stops re-inventing its page structure with raw rows and columns: <app-form-section> groups related fields under a title and optional description, <app-form-row> lays fields out in a responsive grid, and <app-form-actions> holds the submit/cancel bar — optionally sticky at the viewport bottom.

They are structure only. Fields inside stay the ordinary <app-input> family; buttons stay <app-button>.

In a real screen

A company settings form as a product would build it: two sections, required fields, validation on Save and an action bar. Switch the section options above it, clear the company name or break the GSTIN, then press Save.

layout
labels
density
Company settings
Shown on invoices and in emails to your customers

Company profile

Your legal details, as registered.

15 characters, printed on your GST certificate.
Logistics Healthcare Education Manufacturing Retail Software Travel

Preferences

How amounts, dates and reminders appear.

Indian rupee (₹) US dollar ($) UAE dirham
India (IST, UTC+5:30) Dubai (GST, UTC+4) London (GMT/BST) New York (ET)
Billing cycle
Press Enter after each tag.
Cancel

Playground

Every attribute across all three tag helpers, live. Each change re-renders the real tag helpers on the server, so the markup underneath is the exact call that produced the form above it.

Personal Details

<app-form-section title="Personal Details">
    <app-form-row columns="2">
        <app-input label="First name" name="firstName" />
        <app-input label="Last name" name="lastName" />
    </app-form-row>
</app-form-section>
<app-form-actions>
    <app-button variant="outline" type="button">Cancel</app-button>
    <app-button variant="primary" type="submit">Save</app-button>
</app-form-actions>

AppFormSection — group related fields

Wraps a set of related fields with a section heading and optional description.

Contact Information

<app-form-section title="Contact Information">
    <app-form-row>
        <app-input label="Email" name="email" type="email" />
        <app-input label="Phone" name="phone" />
    </app-form-row>
</app-form-section>

Billing Address

Where you want invoices sent

<app-form-section title="Billing Address" description="Where you want invoices sent">
    <app-form-row>
        <app-input label="Street" name="street" />
        <app-input label="City" name="city" />
    </app-form-row>
</app-form-section>

Layout, labels and density

Three section options for longer forms. Each folds back to the stacked, labels-on-top look on smaller screens, so a form never squeezes on a phone.

Notifications

Where we send alerts.

<app-form-section title="Notifications" description="Where we send alerts." layout="side">
    <app-form-row>
        <app-input label="Email" name="email" type="email" />
        <app-input label="Phone" name="phone" />
    </app-form-row>
</app-form-section>

Account

We never share it.
<app-form-section title="Account" labels="start">
    <app-form-row>
        <app-input label="Display name" name="displayName" />
        <app-input label="Email" name="email" type="email" hint="We never share it." />
    </app-form-row>
</app-form-section>

Filters

<app-form-section title="Filters" density="compact">
    <app-form-row columns="3">
        <app-input label="Customer" name="customer" />
        <app-input label="Invoice" name="invoice" />
        <app-input label="Amount" name="amount" />
    </app-form-row>
</app-form-section>

AppFormRow — responsive field grid

Arranges fields in a grid with responsive column collapse.

<app-form-row columns="2">
    <app-input label="First name" name="firstName" />
    <app-input label="Last name" name="lastName" />
</app-form-row>
<app-form-row columns="1">
    <app-input label="Full width field" name="fullName" />
</app-form-row>
<app-form-row columns="3">
    <app-input label="Day" name="day" />
    <app-input label="Month" name="month" />
    <app-input label="Year" name="year" />
</app-form-row>

AppFormActions — button footer

Holds action buttons at a form's end — typically a submit/cancel pair.

<app-form-actions>
    <app-button variant="primary" type="submit">Save</app-button>
</app-form-actions>

<app-form-actions align="start">
    <app-button variant="outline" type="button">Cancel</app-button>
</app-form-actions>
<app-form-actions align="between">
    <app-button variant="outline" type="button">Cancel</app-button>
    <app-button variant="primary" type="submit">Submit</app-button>
</app-form-actions>
<app-form-actions sticky="true">
    <app-button variant="primary" type="submit">Confirm</app-button>
</app-form-actions>

Composing a complete form

Combine the three helpers to build a standard form layout — sections, rows within each, actions at the end.

Profile

How you appear to your team.

<app-form-section title="Profile" description="How you appear to your team.">
    <app-form-row columns="2">
        <app-input label="First name" name="first" />
        <app-input label="Last name" name="last" />
    </app-form-row>
</app-form-section>
<app-form-actions align="end">
    <app-button variant="secondary" type="button">Cancel</app-button>
    <app-button variant="primary" type="submit">Save changes</app-button>
</app-form-actions>

On a long form, sticky="true" pins the action bar to the viewport bottom with a top border and surface background, so Save is always reachable.

Responsive & accessible

All three helpers are fully responsive and accessible — grids collapse to 1 column on mobile, buttons stack when needed, sticky footers keep actions visible.

  • app-form-row collapses below the md breakpoint, letting each field take full width on phones.
  • app-form-actions uses flexbox to align and wrap buttons naturally; sticky mode adds a top border so users know what's pinned.
  • app-form-section stacks vertically and leaves room for tall content, maintaining a readable column width on all screens.

When to use

Use it when

  • You're building a form page — use all three helpers together for a consistent layout.
  • You need to group logically related fields — AppFormSection wraps them with a title.
  • You have multiple fields in a row — AppFormRow arranges them responsively.
  • You're adding action buttons (submit, cancel, etc.) — AppFormActions keeps them aligned.

Reach for something else when

  • You're placing a single isolated field. → just use AppInput directly
  • Your form is a dialog/modal. → AppModal / AppConfirmDialog owns the footer logic
  • You need a custom grid layout. → use Bootstrap Row/Col for full control

Every option

The whole surface of all three helpers, one cell per value.

app-form-section — title / description combinations

(no title, no description)
title only

Preferences

description only

A description renders on its own too

title + description

Preferences

Control how you are notified

app-form-section — layout, labels and density, every value

layout="stacked"

Profile

Your public details.

layout="side"

Profile

Your public details.

labels="top"

Profile

Your public details.

labels="start"

Profile

Your public details.

density="comfortable"

Profile

Your public details.

density="compact"

Profile

Your public details.

app-form-row — columns, every value

columns="1"
columns="2"
columns="3"

app-form-actions — align, every value

align="end"
align="start"
align="between"

app-form-actions — sticky

(default) — flows with the page
sticky="true" — pinned to the bottom of the scroll container with a top border
sticky="true" align="between"

Attributes

app-form-section

AttributeTypeDefaultDescription
titlestringSection heading.
descriptionstringIntro text under the title. Renders on its own when there is no title.
layoutstacked | sidestackedside puts the title and description in a column beside the fields from lg up; below that the section stacks.
labelstop | starttopstart puts each label beside its control, one field per row, from md up; below that labels sit on top.
densitycomfortable | compactcomfortablecompact uses 36px controls and tighter gaps, for admin screens and dialogs.

app-form-row

AttributeTypeDefaultDescription
columns1 | 2 | 32Field columns on desktop; collapses to one under the md breakpoint.

app-form-actions

AttributeTypeDefaultDescription
stickybooleanfalsePin the bar to the viewport bottom with a top border and surface background.
alignend | start | betweenendHorizontal placement of the buttons.