-
Notifications
You must be signed in to change notification settings - Fork 15
Help Page House Style
Every module in FreeITSM has an in-app guide β 26 pages in all, from tickets/help.php down to workflow/help-ssl.php. They all look the same because they all use one stylesheet: assets/css/help.css.
This page is the rule they follow. Read it before writing a new guide, and before adding anything to an existing one.
Until August 2026 there was no house style. There were 26 copies of one.
Each guide carried its own <style> block β the same ~280 lines of layout under its own prefix: cal-help-*, ct-help-*, kb-help-*, tk-help-*, wt-help-*, and a dozen more. Every copy was individually reasonable. The problem was that changing one never changed the others, so they drifted:
- The CMDB guide tinted sections 2, 4 and 8 with a grey band, for no rule anyone could state β and those sections bled 48px wider than their neighbours, so "level 1" appeared to be a different width depending where you were on the page.
-
.cmdb-help-section > phad no indent at all, so three paragraphs sat at level 1 while the steps and cards beside them were indented. Three others had been patched by hand with an inlinestyle="margin-left:46px". - Twelve pages hand-coloured their feature icons blue / green / orange / purple down a single grid.
- Seven different class names β
tip,callout,warn,gotcha,danger,consequence,exampleβ did the job of one. - Most pages simply
display: noned their contents list below 900px.
7,657 lines of duplicated styling became 600. The rest of this page is what replaced it.
This is the rule. Everything else is detail.
level 1 .help-section full width of the pane, NEVER indented
.help-section-header (number) + <h3> + lead <p>
level 2 everything else in it indented to --help-indent
level 3 .help-subsection its <h4> sits at level 2,
its content one step further in
A guide reads as a numbered list of sections. Each section spans the full width; everything belonging to that section lines up underneath its heading. That holds at every screen size β on a phone the indent shrinks from 46px to 32px along with the badge that sets it, rather than collapsing to the left edge.
The old pages put margin-left: 46px on each individual component, which is exactly why the occasional paragraph fell out of line β somebody added a <p> and there was nothing to remind them. The house style does it the other way round:
.help-section {
padding-left: var(--help-indent); /* everything inside starts here */
}
.help-section-header {
margin-left: calc(var(--help-indent) * -1); /* except the heading, which backs out */
}Anything you drop into a section is aligned correctly by default, and there is no way to forget. Never add margin-left to a help page to line something up by hand β if it isn't aligned, the markup is in the wrong place.
Every section looks identical: number badge, heading, indented body, a hairline rule to the next one. There is no "highlighted section" variant, deliberately. A variant that means nothing in particular gets applied inconsistently, which is how this whole mess started. If a section needs to stand out, that is a job for its words.
body {
--accent: var(--cmdb-accent);
--accent-hover: var(--cmdb-accent-hover);
--accent-soft: var(--cmdb-accent-soft);
--on-accent: var(--cmdb-on-accent);
}Four lines. assets/css/help.css draws everything β the hero gradient, the badges, the note callouts, the card icons, the flow steps β from those four variables. Every module already defines its own set in assets/css/theme.css, in both light and dark palettes, so nothing else needs writing. See Theming & Dark Mode for where those tokens come from.
Tickets is the one exception: it has no accent of its own and uses the application's brand colour, which assets/css/help.css already reads from the global --accent. Its style block says exactly that and nothing else.
The sweep had to decide, a dozen times, whether a splash of colour was information or decoration. The rule that settled it:
Colour that carries the meaning stays. Colour that only repeats the label sitting next to it goes.
| Kept β the colour is the information | Removed β the label already said it |
|---|---|
| Service-status dots (operational / degraded / maintenance / outage) | Feature-card icons in four unrelated colours down one grid |
| The morning-checks red/amber/green trend bars and its three RAG cards | Flow-chain steps in a per-module rainbow |
| Change types (standard / normal / emergency) and the change lifecycle badges | Knowledge's pending / approved / rejected card borders |
| The change risk scale, green through to deep red | Contracts' four coloured dots beside settings headings |
| Watchtower's status dots; the LMS progress pills; the mailbox-auth badges |
Everything in the "kept" column was moved onto the theme's semantic tokens (--success-*, --warning-*, --danger-*) on the way through, because the originals were hardcoded pastels that only worked in light mode.
Don't build the hero banner from accent β accent-hover. On dark palettes the module accents are deliberately lifted so they read on dark surfaces, so a full-bleed banner made from them glares. assets/css/help.css handles this already:
.help-hero { background: linear-gradient(135deg, var(--accent) 0%, var(--accent-hover) 100%); }
[data-theme-mode="dark"] .help-hero {
background: linear-gradient(135deg, var(--accent-soft) 0%, var(--surface-2) 100%);
color: var(--text);
}Colour key: π§± page skeleton Β· π body copy Β· ποΈ grouped content Β· π·οΈ inline Β· π» code & tables
| π¨ | Class | What it is |
|---|---|---|
| π§± | .help-container |
the flex shell; also where the --help-indent / --help-gutter variables live |
| π§± |
.help-sidebar + h3
|
the fixed contents rail; h3 is a group heading |
| π§± |
.help-nav-link + .help-nav-num
|
one entry; add .active for the current section |
| π§± | .help-main |
the scrolling column (the scroll-spy listens on this, not window) |
| π§± | .help-hero |
the banner; takes <h1> or <h2>
|
| π§± | .help-content |
the padded column the sections sit in |
| π§± |
.help-section + -header + -num
|
level 1 β see the heading model above |
| π | .help-subsection |
level 3 β a titled block within a section |
| π | plain <p>, <ul>, <ol>, <h4>, <h5>
|
styled as direct children of .help-section; no class needed |
| π | .help-lede |
the one sentence that sets up a whole guide |
| π | .help-note |
a callout. Modifiers: .warn, .bad, .ok. Plain = the module accent |
| π | .help-back |
"β Back to β¦" on a deep-dive page hanging off another guide |
| π | .help-muted |
an aside within a paragraph |
| ποΈ |
.help-cards + .help-card
|
the card grid. Modifiers .cols-1 / .cols-3 / .cols-4; 2 is the default |
| ποΈ | .help-card-icon |
the tinted icon tile. .plain for an emoji (no tile) |
| ποΈ | .help-card.row |
the one sanctioned card variant: icon left rather than above |
| ποΈ | .help-card-eg |
the italic "e.g. β¦" line at the foot of a card |
| ποΈ |
.help-steps + .help-step + .help-step-num
|
a numbered procedure |
| ποΈ |
.help-defs + .help-def + -term + -desc
|
term-and-definition rows |
| ποΈ | .help-list |
a plain stack of tinted rows |
| ποΈ |
.help-flow + .help-flow-step + .help-flow-arrow
|
A β B β C. Steps are neutral; .accent marks one |
| ποΈ |
.help-diagram + -node + -line
|
a monospace tree drawing |
| ποΈ | .help-timeline |
a worked example told in order |
| π·οΈ | .help-pill |
a status tag. Modifiers .ok .warn .bad .info; plain = neutral |
| π·οΈ | .help-dot |
a small coloured status dot |
| π» |
.help-code, <pre>
|
a code block (same dark scheme in both themes β a terminal should look like a terminal) |
| π» |
<code>, .help-kbd
|
inline identifier; a keyboard key |
| π» | .help-table |
a wrapper <div> around the <table>, so a wide table scrolls inside its section instead of stretching the page |
Note the pill and note modifiers are named for what they mean, not for a colour β .help-note.bad, not .help-note.red. That is what lets them follow the theme.
<link rel="stylesheet" href="../assets/css/theme.css?v=22">
<link rel="stylesheet" href="../assets/css/inbox.css">
<link rel="stylesheet" href="../assets/css/help.css?v=1">
<style>
/* The only thing a help page should need to say for itself: its colour. */
body {
--accent: var(--mymod-accent);
--accent-hover: var(--mymod-accent-hover);
--accent-soft: var(--mymod-accent-soft);
--on-accent: var(--mymod-on-accent);
}
</style><div class="help-container">
<div class="help-sidebar">
<h3>Guide</h3>
<a href="#overview" class="help-nav-link active" data-section="overview">
<span class="help-nav-num">1</span> Overview
</a>
</div>
<div class="help-main" id="helpMain">
<div class="help-hero">
<h2>My module guide</h2>
<p>One sentence on what the module is for.</p>
</div>
<div class="help-content">
<div class="help-section" id="overview">
<div class="help-section-header">
<span class="help-section-num">1</span>
<div>
<h3>Overview</h3>
<p>The lead paragraph.</p>
</div>
</div>
<!-- everything from here is level 2 and indents itself -->
<p>Body copy.</p>
<div class="help-cards">β¦</div>
<div class="help-note">A tip.</div>
</div>
</div>
</div>
</div>Copy the scroll-spy script from any existing guide β it listens on #helpMain and filters on [data-section].
If you find yourself adding layout CSS to a help page, it belongs in assets/css/help.css so every module gets it. What legitimately stays in a page is a diagram of that module and nothing else: the knowledge guide's mock AI conversation, morning checks' trend chart, watchtower's drawing of a real module card, contracts' tab strip, the change lifecycle, the RFP phase strip. Everything else has a 5-to-9-line style block.
Worth knowing before you rename anything.
lang/en/tickets.php contained <span class="tk-help-code">. lang/*/process-mapper.php had pm-help-kbd. lang/*/lms.php had lh-pill β across all 21 locales. A grep of the .php pages reports "clean" while the rendered page is broken.
After any class rename in a help page, grep
lang/as well.
Two failures, both from the same cause:
-
self-service numbered two of its nine sections with an empty badge. The numbers were hardcoded in the headings, two sections had been inserted later, and JavaScript patched the numbers at runtime to paper over it. It now derives the number from the
$helpNavarray in PHP, so the heading and the sidebar cannot disagree β and it no longer needs JS to show a number at all. -
workflow rendered "1." twice, once in the badge and once in the heading text, because the number was baked into the translation string. Stripped from the ten headings in
en,pt-BRandukβ and note that only 3 of 21 locales had ever carried them, which is its own argument for keeping numbers out of prose.
Two pages had <table class="help-table">. It needs to be <div class="help-table"><table>β¦</table></div> or a wide table stretches the whole page instead of scrolling inside its section.
Two throwaway scripts earned their keep and are worth rebuilding if you do this again:
-
An orphan-class check β extract every
class="β¦"from the markup, and confirm each name has a rule in some stylesheet the page actually links (parse the<link>tags rather than assuming). This is what catches a rename that dropped a rule on the floor: a modifier like.tag.greenwhose CSS went with the deleted style block, so the badge silently renders plain. -
A fetch-and-read check β pull every help page over HTTP with a forged session and read the body, not the status code. A PHP fatal is served as HTTP 200, so a status-only check reports a broken page as a pass. While you have the HTML, grep it for unresolved
*.help.*keys β a missing translation falls back to printing the key.
Then a console-error pass in headless Chrome across every page β with a negative control, so you know the check can actually fail. Injecting a call to an undefined function into one copy and confirming the check catches it takes ten seconds and is the difference between "no errors" and "no detection".
Two things to know when doing this locally:
- The portal page needs an
ss_user_idsession, notanalyst_id. -
system/integrations/help.phpredirects without a?provider=parameter.
-
Theming & Dark Mode β where the
--accent/--surface/ semantic tokens come from - Mobile: Techniques & Tricks β the wider rules for narrow screens
-
Internationalisation (i18n) β why help text lives in
lang/, and the parity rules - Architecture β where help pages sit in the file layout
FreeITSM β an open-source IT Service Management platform Β· github.com/edmozley/freeitsm Β· MIT licence
- Installation
- β° Scheduled tasks (cron jobs)
- Architecture
- AI Providers
- Internationalisation (i18n)
- Timezones & Time Handling
- Theming & Dark Mode
- β¨οΈ Command palette (βK)
- π Searching inside tickets
- π Attached documents
- MobileβFriendly
-
Security
- Layer 1 β which modules you can enter
- β³ π§© Module Access Control
- β³ π οΈ Module Access β Developer Guide
- Layer 2 β what you can administer
- β³ π Roles & Permissions
- β³ π οΈ Roles β Developer Guide
- β³ π€ Why capabilities are constants
- Layer 3 β the System module
- β³ π Admin Access Control
- Hardening
- β³ π Security review response 2026-08
- β³ π‘οΈ Security hardening 2026-08
- β³ π οΈ Security hardening 2026-08 β Developer Guide
- β³ π‘οΈ Round three β plain English
- β³ π οΈ Round three β Developer Guide
- Single Sign-On (SSO)
- ποΈ LDAP & Active Directory
- Browser Extension
- API Reference
-
π REST API β how it works
- β³ π« REST API: Tickets
- β³ π» REST API: Assets
- β³ π΄ REST API: Problems
- β³ π REST API: Changes
- β³ π REST API: Knowledge
- β³ β REST API: Tasks
- β³ ποΈ REST API: CMDB
- β³ π REST API: Contracts
- β³ ποΈ REST API: Calendar
- β³ πΏ REST API: Software
- β³ π¦ REST API: Service Status
- β³ βοΈ REST API: Morning Checks
- β³ π REST API: Forms
- β³ βοΈ REST API: Workflow
- β³ πΊοΈ REST API: Network Mapper
- β³ π§ Using the API docs page
- β³ π OpenAPI specification
- β³ β OpenAPI: kept correct
- β³ π οΈ Maintaining the catalogue
- Watchtower
-
Tickets
- β³ Mailbox Authentication
- β³ π€ Email send log
- β³ Basic IMAP mailboxes
- β³ Email rendering & images
- β³ SLA Management
- β³ WhatsApp channel
- β³ π¬ Web chat channel
- β³ π£ Slack channel
- β³ π Linking tickets
- β³ ποΈ Canned responses
- β³ βοΈ Limiting replies to particular senders
- β³ βοΈ Email signatures
- β³ π The public web address
- β³ π’ Ticket numbering
- β³ π Raising a ticket for someone else
- β³ π Merging tickets
- β³ β Splitting tickets
- β³ β Selecting several tickets
- β³ π οΈ Snoozing tickets β Developer Guide
- β³ π₯ Collision detection
- β³ β±οΈ Time tracking
- Problem Management
- Tasks
- Assets
- Knowledge
- Change Management
- Calendar
- Morning Checks
- Reporting
- Software
- Forms
- Contracts
- Service Status
- π Notifications
- π¨ War Room
- Self-Service Portal
- LMS
- Process Mapper
- CMDB
- Network Mapper
- Workflows
- Issue trackers (Jira, Azure DevOps)
- System
-
Overview
- β³ π Progress tracker
- β³ Concepts & vocabulary
- β³ Email routing & mailboxes
- β³ Settings: global vs per-company
- β³ Users & self-service
- β³ Staff cross-company access
- β³ Worked examples
- β³ Pitfalls & gotchas
- β³ Scope: what it's for
- β³ π οΈ Developer Guide (make a module multi-company)
- β³ ποΈ Case study: CMDB (a linked graph)
- β³ π§ͺ Test harness (prove it's isolated)