Skip to content

System Page Layout

Ed Mozley edited this page Nov 14, 2026 · 1 revision

πŸ“ System page layout - Developer Guide

Since 5.3.0 Β· Related: UI style guide Β§3 Full width, Help page house style

Every System screen uses one page layout, defined once and checked in a browser. Before this, each page carried its own container and heading rules, and they had drifted:

Measured at 1600px, before
Left gutter 20, 24, 28, 32 or 40px - and 416px on Encryption and Docker (an 800px centred column)
Page title h1 or h2, 22 or 24px, weight 600 or 700, 62-98px from the top
Panels and intros capped at 720-900px on 18 pages
Height 20 pages ran 14px past the bottom of the window (sized as 100vh - 48px; the header is taller than 48px)

1. πŸ“ Files

File Role
assets/css/system-page.css The layout. .sys-page, .sys-page-head, .sys-title, .sys-subtitle, .sys-actions, .sys-panel, and the desktop height rule
system/includes/header.php Loads it - so every System page has it without its <head> remembering, and after the page's own <style>, so it wins a tie
tests/system-page-layout.php Opens every System screen in headless Chrome and measures it (Β§4)

2. 🧱 The markup

<div class="xx-container sys-page">              <!-- the page's content box -->
  <div class="sys-page-head">
    <div>
      <h1 class="sys-title">Cost Centres</h1>
      <p class="sys-subtitle">What this page is for.</p>
    </div>
    <div class="sys-actions"> <!-- optional: primary buttons, on the right -->
      <button class="btn btn-primary">Add</button>
    </div>
  </div>
  <div class="sys-panel"> ... </div>              <!-- optional white card -->
</div>
  • A page keeps its own class on the content box (.cc-container) as well as sys-page, so its own rules for things inside it - and mobile.css's rules for it - still apply. Only width, margin, padding and the title rules move to the shared file.
  • A back link or breadcrumb stays above .sys-page-head.

3. πŸ”‘ The rules it enforces

  • Full width, one gutter. .sys-page is width: 100%; max-width: none; margin: 0; padding: 24px 32px 40px (16px on a phone).
  • One title. 22px, weight 700 (19px on a phone).
  • No cap of your own. ⚠️ This is the one that keeps coming back: a "tasteful" 760px reading measure on a panel or an intro is still a cap (it bit System β†’ Search, Tickets β†’ Indexing, Forms β†’ Collections and System β†’ Locations). Caps belong only on controls: a search box, a single input or select, a form group holding one input, a table cell, an image, a modal. Anything else that genuinely needs one says so with data-sys-cap="why" - e.g. the portal mock-up on Self-service, the shared AI settings panel (includes/ai_settings_panel.php caps itself at 640px).
  • Height. On a desktop, when .sys-page is the body's own child, the body becomes a flex column: the header takes its real height and the page fills the rest and scrolls (body:has(> .sys-page)). Pages with another wrapper (a .main-container, a .settings-shell) already did this themselves. Never size a page as calc(100vh - 48px).

4. πŸ§ͺ The test

FREEITSM_TEST_DATABASE=freeitsm_prtest FREEITSM_TEST_URL=http://localhost/freeitsm-prtest php tests/system-page-layout.php
FREEITSM_SPL_ONLY=cost-centres,sso/entra.php ...   # just those

It finds the pages itself - every card in getSystemAreas() plus every other system/*/*.php that includes the System header - so a new page is checked the day it exists. For each, at 1600px:

  1. the .sys-page fills the width it is given (the parent's inner width, scrollbar excluded);
  2. its gutter is 32px;
  3. its .sys-title sits on the gutter at 22px / 700;
  4. nothing inside is capped (a visible block 400px+ wide held narrower than the page by a max-width, controls and data-sys-cap excepted);
  5. the page ends inside the window - no second scrollbar, the bottom reachable.

Pages that only open for a record get one: three temporary ZZ layout test sign-in providers (LDAP, Entra, CardDAV), removed in finally, and the first tracker in the integrations registry. Each Chrome run has its own profile, so two runs at once do not collide.

Not checked, on purpose ($APP_PAGES, with the reason printed): the Engineering Wiki and the API reference, which are document readers with their own navigation, and the help pages (system/help/, */help.php), which follow the Help page house style.

5. βœ… Adding a System page

Use the markup in Β§2, put no max-width on anything but a control, and run the test with FREEITSM_SPL_ONLY=<your page>. Five passes and it is done.

FreeITSM

Getting Started

Modules

Multi-tenancy (planned)

Responses to feedback

Blue sky thinking

Bugs resolved

Pull requests

Links

Clone this wiki locally