Skip to main content
Version: V3

Layout Templates

Themes and templates

A theme sets colors, the logo, and other visual options. A layout template changes page structure. A theme can use one layout template (chosen on the theme's Advanced tab), and several themes can share the same template. With no template assigned, the panel uses its built-in layout.

Creating a template

  1. Go to Settings → Layout Templates and create a template.
  2. Add one or more surfaces (for example LoginPage or Shell) and edit each surface's markup and CSS. Use Validate / Preview to check a surface as you work.
  3. Save the template, then open a theme's Advanced tab and choose it. Select that theme to see it in action.
Locked out by a template?

Add ?safeMode=1 to the panel's address to temporarily ignore the template's markup and CSS and fall back to the built-in layout — handy if a custom login or shell ever renders incorrectly.

How a surface is written

A template is organized into surfaces — named regions you can take over (the login page, the whole shell, or individual parts of the shell). In a surface you write ordinary HTML with three special tags:

  • {{ Variable }} — inserts a value, such as the application name or the signed-in user.
  • {% component "name" %} — drops in a live, interactive piece of the panel (the login form, the navigation menu, the dark-mode toggle, and so on).
  • {% surface "Key" %} — places one of the customizable regions inside your shell.

Each surface also has its own CSS box, and the template has a base stylesheet that applies whenever the template is active. The editor's Reference tab lists every available variable, component, and surface key.

note

Templates imported from others run in a safe mode that strips scripts, so a shared template can't run code. Some advanced CSS (for example blur or animations) is also filtered unless an administrator marks the theme as trusted.

Variables

Insert a variable with {{ AppName }}, or the dotted form for nested values such as {{ Branding.Title }}. Output is automatically HTML-encoded.

VariableTypeDescription
AppNamestringThe application name.
AppVersionstringThe running version.
CulturestringThe current language code.
IsAuthenticatedbooleanWhether the visitor is signed in.
UserNamestringThe signed-in user's name.
Branding.TitlestringThe branding title.
Branding.SubtitlestringThe branding subtitle.
Branding.LogoUrlstringThe branding logo image URL.

Components

Add a component with {% component "name" %}. The most useful ones:

ComponentWhat it adds
login-formThe sign-in form (required somewhere on the login page).
brandThe logo and branding block.
shellThe entire built-in shell — a quick base when you only want to restyle with CSS.
bodyThe current page's content (required somewhere in a custom shell).
menuThe navigation drawer and menu.
menu-toggleThe button that opens and collapses the drawer.
topbarThe complete built-in top bar.
breadcrumbsThe breadcrumb trail.
dark-mode-toggleThe light / dark switch.
language-selectorThe language picker.
connection-statusA warning shown only when the live connection drops.
connection-indicatorAn always-on connection dot (green / amber / red).
health-indicatorA system-health indicator (shown only to permitted users).
announcementsThe customer announcements control.
footer-resourcesThe current page's live stats — a game or Docker server's disk, CPU, memory, network and players.

The surfaces

Login page

The LoginPage surface replaces the entire login page. It must include the login-form component, or no one could sign in.

<div class="login-glass-card">
<h2>🎨 My Custom Login Template</h2>
<p>{{ Branding.Title }} — v{{ AppVersion }}</p>
{% component "brand" %}
{% component "login-form" %}
{% component "language-selector" %}
</div>

App shell

The Shell surface replaces the shell that wraps every page. It must include either the body component (the page content) or the shell component (the entire built-in shell). The example below rebuilds the shell from individual pieces — a custom top bar, the menu, the page body, and the footer region — and places the top-bar and footer surfaces inside it.

When you hand-build the shell like this, one CSS rule is required so the navigation drawer sits correctly below your top bar — it's the first rule in the CSS tab below.

<div class="tca-shell-header">
{% component "menu-toggle" %}{% surface "Shell.TopBarStart" %}
<span class="tca-shell-title">{{ AppName }}</span>
{% component "breadcrumbs" %}
<span class="tca-shell-spacer"></span>
{% component "connection-status" %}{% component "dark-mode-toggle" %}{% surface "Shell.TopBarEnd" %}
</div>
{% component "menu" %}
<div class="tca-shell-body">
{% component "body" %}
</div>
{% surface "Shell.Footer" %}
Just restyling?

If you only want to recolor or restyle the panel without rebuilding it, make your Shell simply {% component "shell" %} and put everything in the stylesheet — you won't need the drawer rule above.

And if you don't need to change the shell's markup or CSS at all, just disable the Shell surface (or leave it out) — the built-in shell is used, and the other surfaces (top bar, drawer, footer and content slots) still appear on their own.

Top bar slots

The Shell.TopBarStart and Shell.TopBarEnd surfaces add extra content at the start (left) or end (right) of the top app bar, alongside the built-in toggles. Both appear automatically in the built-in top bar; in a hand-built Shell you position them with {% surface "Shell.TopBarStart" %} / {% surface "Shell.TopBarEnd" %}, as shown in the shell example above.

<!-- Shell.TopBarStart -->
<div class="tca-topbar-start">
<span class="tca-topbar-start-icon">&#9889;</span>
<span>Status: Online</span>
</div>
<!-- Shell.TopBarEnd -->
<div class="tca-topbar-end">
<span class="tca-topbar-end-icon">&#9733;</span>
<span>Pro Plan</span>
</div>

Shell.DrawerHeader and Shell.DrawerFooter add content above or below the navigation menu inside the drawer — for example a brand zone at the top, or an account and sign-out block at the bottom.

<!-- Shell.DrawerHeader -->
<div class="tca-drawer-header">
<div class="tca-drawer-header-logo">&#9889;</div>
<div>
<div class="tca-drawer-header-name">{{ AppName }}</div>
<div class="tca-drawer-header-sub">{{ Branding.Subtitle }}</div>
</div>
</div>
<!-- Shell.DrawerFooter -->
<div class="tca-drawer-footer">
<span class="tca-drawer-footer-dot"></span>
<span class="tca-drawer-footer-text">Signed in as <strong>{{ UserName }}</strong></span>
</div>

Before and after content

Shell.BeforeContent and Shell.AfterContent are banner strips shown immediately above or below the page content, on every page.

<!-- Shell.BeforeContent -->
<div class="tca-before-content">
<span class="tca-before-content-icon">&#8505;</span>
<span>Scheduled maintenance this Sunday at 02:00 UTC.</span>
</div>
<!-- Shell.AfterContent -->
<div class="tca-after-content">
&copy; {{ AppName }} — all rights reserved.
</div>

The Shell.Footer surface replaces the contents of the footer bar. If you don't define it, the built-in footer is shown.

<div class="tcf">
{% component "health-indicator" %}
<a class="tcf-link" href="/support">Support</a>
<a class="tcf-link" href="https://status.example.com" target="_blank" rel="noopener">Status</a>
<span class="tcf-grow"></span>
<span class="tcf-brand">&copy; 2026 {{ Branding.Title }}</span>
<span class="tcf-ver">v{{ AppVersion }}</span>
{% component "connection-indicator" %}
</div>
tip

Add {% component "footer-resources" %} to a custom footer to show the current page's live stats — a game or Docker server's disk, CPU, memory, network and players.

The Shell.MenuLinks surface adds your own links to the end of the navigation menu, styled to match the built-in items. To look native, each link uses the same markup as the built-in items: an <a class="mud-nav-link"> containing a Font Awesome icon and a text label.

<a href="https://docs.tcadmin.com" target="_blank" rel="noopener noreferrer" class="mud-nav-link mud-ripple">
<i class="fa-solid fa-book mud-icon-root mud-nav-link-icon mud-nav-link-icon-default" style="font-size:24px;width:24px;text-align:center;"></i>
<div class="mud-nav-link-text">Documentation</div>
</a>
<a href="https://help.tcadmin.com" target="_blank" rel="noopener noreferrer" class="mud-nav-link mud-ripple">
<i class="fa-solid fa-life-ring mud-icon-root mud-nav-link-icon mud-nav-link-icon-default" style="font-size:24px;width:24px;text-align:center;"></i>
<div class="mud-nav-link-text">Support</div>
</a>
note

Use Font Awesome icons (<i class="fa-solid ...">). Keep the mud-icon-root class so the label collapses to an icon-only button when the drawer is minimized.

Sharing templates

A finished template can move between installations:

  • Export / Import — from a template's editor, Export downloads it as a file; Import on the Layout Templates list loads one back in.
  • Plugin RepositoryShare publishes a template to a connected plugin repository, where other installations can browse and install it. You can also share a theme together with its template as a single bundle, so the colors and the layout travel together.