Skip to content

Page Layout

Overview

Bellini offers three approaches to building reusable page layouts. Nested pages let you use a parent page as a layout shell — containing the nav, header, footer, and overall structure — while all other pages are nested as children inside it. The parent renders consistently on every route, and only the child page content changes. Layout components with Layout Fragment achieve a similar result through a reusable component with a defined content slot, which can be placed on each page. Individual shared components are a simpler option for placing discrete elements like a header or footer on each page manually.

What You Will Learn

  • How to use a parent page as a layout shell so all child pages share a common structure
  • How to create a layout component with a content slot using Layout Fragment
  • How to use a layout component on a page and add page-specific content
  • Which built-in layout components are useful for structuring page layouts
  • How to share discrete elements across pages using individual components

When To Use This

Use this page when you want to share a consistent structure — such as a header, navigation bar, or footer — across multiple pages in your application without duplicating it on every page.


Choosing an Approach

Nested Pages Layout Component Individual Components
Layout defined in A parent page A component Separate components per element
Applied to pages by Nesting child pages inside the parent Placing the component on each page Placing each component on each page
URL reflects hierarchy Yes No No
Child pages are independent routes Yes N/A N/A
Layout changes propagate automatically Yes Yes Per component
Works in components No — pages only Yes Yes
Best for App-wide shell layout Reusable layout outside of routing Simple or varied per-page structure

Use Nested Pages when

  • You want a consistent app-wide shell (header, nav, footer) across all or most pages.
  • You want the URL to reflect the full page hierarchy.
  • Your child pages need to be independently navigable at their own routes.
  • You want layout changes to apply automatically without touching individual pages.

Use a Layout Component when

  • You want a reusable layout that is not tied to routing.
  • You need the layout to work in both pages and components.
  • You want to define a content slot (via Layout Fragment) that each page fills differently.
  • You want layout changes to propagate automatically to all pages that use the component.

Use Individual Shared Components when

  • Different pages have significantly different structures and only share a few discrete elements (e.g. just a header).
  • You want the simplest possible approach with no routing constraints.
  • You are building a small application or prototyping quickly.

Approach 1: Nested Pages

Nested pages let you create a layout shell page — a parent page that contains the shared structure of your application (navigation, header, footer) but no page-specific content of its own. All the real pages of your application are then nested as child pages inside it. Because the parent page remains active across all child routes, its layout is always visible while only the child page content changes.

For example, you might have a shell page at / that contains the navigation bar and footer. Every other page in the application — orders at /orders, dashboard at /dashboard, settings at /settings — is nested inside shell as a child. Navigating between those pages updates the URL and swaps the child page content area, while the nav and footer stay in place.

What the user sees in the browser:

graph TD
    subgraph shell["Shell Page — always visible"]
        H["Header"]
        N["Navigation Bar"]
        subgraph content["Content Area"]
            C["Active child page renders here"]
        end
        F["Footer"]
    end

How the pages are structured:

graph TD
    shell["shell (/)"] --> orders["orders (/orders)"]
    shell --> dashboard["dashboard (/dashboard)"]
    shell --> settings["settings (/settings)"]

Nested pages can also be used for master-detail patterns: a parent page at /contacts displays a contact list and embeds a child page at /contacts/:contactName that shows the contact details. Selecting a contact renders the detail page inside the list page and updates the URL to /contacts/JohnDoe — without replacing the list.

Path Requirement

The child page's path must start with the parent page's path. For example:

Parent path Valid child path
/contacts /contacts/:contactName
/orders /orders/:orderId/details

If the child page path does not start with the parent page path, Bellini will display a validation error:

The child page must have a path that starts with the parent page path. e.g. "/contacts" and "/contacts/details/:contactId".

Embedding a Child Page

  1. Create both the parent page and the child page, ensuring the child's Path starts with the parent's Path. See Page Configuration.
  2. Open the parent page in the Page Editor.
  3. Drag the child page from the Apps view and drop it onto the parent page's canvas or into a container element in the Elements Tree.
  4. The child page appears under a child-pages item in the Elements Tree, displayed as pageName /pagePath. The child page's full content renders in the editor at its dropped position.

Multiple child pages can be added to the same parent. Only one child page is displayed at a time, determined by the current URL — whichever child page path matches the current route is the one rendered.

A child page can still be navigated to directly on its own; nesting does not remove it from the application's routing.

Automatic Path Update

When you drop a child page into a parent page, Bellini automatically updates the child page's path to be relative to the parent. For example, dropping a page with path /order into a parent page with path /home will update the child page path to /home/order.

Circular Nesting Prevention

Bellini prevents circular nesting. If you attempt to drop a parent page into one of its own child pages, the drop is rejected and Bellini notifies you that circular nested pages have been detected.


Approach 2: Layout Component with Layout Fragment

This approach is useful when you want a single component to define the full page structure (header, nav, content area, footer) and each page only fills in the content area.

What the layout component looks like:

graph TD
    subgraph component["page-layout Component"]
        H["Header"]
        N["Navigation Bar"]
        subgraph fragment["Layout Fragment — content slot"]
            C["Page-specific content renders here"]
        end
        F["Footer"]
    end

How pages share the component:

graph TD
    layout["page-layout Component"] --> orders["orders page"]
    layout --> dashboard["dashboard page"]
    layout --> settings["settings page"]

Step 1: Create the Layout Component

  1. In the Apps view, right-click Components under your application.
  2. Select New > Component and give it a descriptive name such as page-layout.
  3. Double-click the component to open it in the Component Editor.

Step 2: Design the Layout

In the component's canvas, build the structural elements that will be shared across pages. Common elements include:

  • A header bar with your application title or logo
  • A navigation component
  • A footer

Use the built-in layout components to structure these elements without writing CSS:

Step 3: Insert a Layout Fragment

Once the structural elements are in place, decide where the page-specific content should appear (typically the main content area between the header and footer). Drop a Layout Fragment component at that position.

The Layout Fragment acts as a named content slot. Any content added to the fragment by a page will be rendered at that position inside the layout component. You can add fallback content under the Layout Fragment — this is displayed when no content has been added by the consuming page.

For full details on Layout Fragment properties and advanced usage (including multiple named fragments), see the Layout Fragment reference.

Step 4: Use the Layout Component on a Page

  1. Open a page in the Page Editor.
  2. Drag the page-layout component onto the page canvas.
  3. In the Elements Tree, expand the page-layout item. You will see a child item named after the Layout Fragment you defined in the component.
  4. Add your page-specific components and content inside that fragment item. They will be rendered inside the layout component at the position of the Layout Fragment.

Repeat steps 2–4 on every page that should use this layout. The shared structural elements (header, nav, footer) are maintained in one place — the component — and any changes to the layout automatically apply to all pages that use it.


Approach 3: Individual Shared Components

A simpler alternative is to create individual components for each shared element — for example, a site-header component and a site-footer component — and place them on each page separately.

This approach is straightforward but requires placing each shared component on every page manually. It works well when pages have different structural arrangements and do not share a single unified layout.

Shared components that are reused across multiple applications should be created as global components (under the Components view in the left sidebar, outside of any specific app). App-scoped components (under an app's Components in the Apps view) are only available within that application.


Helpful Resources

  • Layout Fragment — Full reference for the Layout Fragment component including multiple named slots
  • Grid — Arrange elements in rows and columns
  • Horizontal Box — Align elements side by side
  • Vertical Box — Stack elements vertically
  • Page Editor — Overview of the canvas and Elements Tree
  • Community Q&A: Bellini Community
    Have a question? Post or search it here.