Skip to content

Form Layouts

Layouts organize how controls are arranged on the form. You can nest layouts inside each other to create complex arrangements.

Layout Types

LayoutDescription
VerticalLayoutStack elements top to bottom
HorizontalLayoutArrange elements side by side
CategorizationTabbed interface
CategoryA single tab (used inside Categorization)

VerticalLayout

Stacks child elements vertically in a single column. This is the most common layout.

yml
uischema:
  type: VerticalLayout
  elements:
    - type: Control
      scope: "#/properties/firstName"
    - type: Control
      scope: "#/properties/lastName"
    - type: Control
      scope: "#/properties/email"

layout-vertical.png

HorizontalLayout

Arranges child elements side by side in a row. Useful for related fields like first/last name or city/state/zip.

yml
uischema:
  type: HorizontalLayout
  elements:
    - type: Control
      scope: "#/properties/firstName"
    - type: Control
      scope: "#/properties/lastName"

layout-horizontal.png

Controlling Column Spacing

Use Vuetify options to control spacing:

yml
uischema:
  type: HorizontalLayout
  options:
    vuetify:
      v-col:
        padding: 0
  elements:
    - type: Control
      scope: "#/properties/field1"
    - type: Control
      scope: "#/properties/field2"

Nesting Layouts

Combine layouts for complex forms. A common pattern is horizontal rows inside a vertical layout:

yml
uischema:
  type: VerticalLayout
  elements:
    # Row 1: First and Last Name side by side
    - type: HorizontalLayout
      elements:
        - type: Control
          scope: "#/properties/firstName"
        - type: Control
          scope: "#/properties/lastName"
    
    # Row 2: Email (full width)
    - type: Control
      scope: "#/properties/email"
    
    # Row 3: City, State, Zip side by side
    - type: HorizontalLayout
      elements:
        - type: Control
          scope: "#/properties/city"
        - type: Control
          scope: "#/properties/state"
        - type: Control
          scope: "#/properties/zip"

Categorization (Tabs)

Creates a tabbed interface. Each tab is a Category element.

yml
uischema:
  type: Categorization
  elements:
    - type: Category
      label: Personal Info
      elements:
        - type: VerticalLayout
          elements:
            - type: Control
              scope: "#/properties/name"
            - type: Control
              scope: "#/properties/email"
    
    - type: Category
      label: Preferences
      elements:
        - type: VerticalLayout
          elements:
            - type: Control
              scope: "#/properties/theme"
            - type: Control
              scope: "#/properties/notifications"

layout-tabs.avif

Category Structure

Each Category must have:

  • type: Category
  • label — Tab title
  • elements — Content (usually starts with a layout)
yml
- type: Category
  label: Tab Title
  elements:
    - type: VerticalLayout
      elements:
        # Controls go here

Always wrap category content

It's best practice to wrap Category contents in a VerticalLayout for consistent spacing.

Complete Examples

Simple Vertical Form

yml
schema:
  type: object
  properties:
    name:
      type: string
    email:
      type: string
    message:
      type: string

uischema:
  type: VerticalLayout
  elements:
    - type: Control
      scope: "#/properties/name"
      label: Name
    - type: Control
      scope: "#/properties/email"
      label: Email
    - type: Control
      scope: "#/properties/message"
      label: Message
      options:
        multi: true

Form with Field Groups

yml
schema:
  type: object
  properties:
    firstName:
      type: string
    lastName:
      type: string
    email:
      type: string
    phone:
      type: string
    addressLine1:
      type: string
    city:
      type: string
    state:
      type: string
    zip:
      type: string

uischema:
  type: VerticalLayout
  elements:
    # Name row
    - type: HorizontalLayout
      elements:
        - type: Control
          scope: "#/properties/firstName"
          label: First Name
        - type: Control
          scope: "#/properties/lastName"
          label: Last Name
    
    # Contact row
    - type: HorizontalLayout
      elements:
        - type: Control
          scope: "#/properties/email"
          label: Email
        - type: Control
          scope: "#/properties/phone"
          label: Phone
    
    # Address
    - type: Control
      scope: "#/properties/addressLine1"
      label: Address
    
    # City/State/Zip row
    - type: HorizontalLayout
      elements:
        - type: Control
          scope: "#/properties/city"
          label: City
        - type: Control
          scope: "#/properties/state"
          label: State
        - type: Control
          scope: "#/properties/zip"
          label: ZIP

Three-Tab Form

yml
uischema:
  type: Categorization
  elements:
    - type: Category
      label: Basic Info
      elements:
        - type: VerticalLayout
          elements:
            - type: Control
              scope: "#/properties/name"
            - type: Control
              scope: "#/properties/email"
    
    - type: Category
      label: Details
      elements:
        - type: VerticalLayout
          elements:
            - type: Control
              scope: "#/properties/description"
              options:
                multi: true
            - type: Control
              scope: "#/properties/priority"
    
    - type: Category
      label: Attachments
      elements:
        - type: VerticalLayout
          elements:
            - type: Control
              scope: "#/properties/files"

Labels

You can add static text labels that don't connect to data:

yml
- type: Label
  text: "Section Title"

Useful for adding instructions or section headers within a form.

Conditional Layout Visibility

Apply rules to show/hide entire layout sections:

yml
- type: VerticalLayout
  rule:
    effect: SHOW
    condition:
      scope: "#/properties/showAdvanced"
      schema:
        const: true
  elements:
    - type: Control
      scope: "#/properties/advancedOption1"
    - type: Control
      scope: "#/properties/advancedOption2"

See Conditional Visibility for more on rules.

Best Practices

  1. Use VerticalLayout as the root — It provides the best default spacing
  2. Wrap Category contents in VerticalLayout — For consistent padding
  3. Group related fields horizontally — Name parts, address components
  4. Keep tab count reasonable — 2-5 tabs is ideal
  5. Use descriptive tab labels — Short but clear (e.g., "Contact", not "Step 2")