Custom layout: Core functionality explained
A detailed guide to the key features, variables, and templating structure available in custom layouts
If you’ve already created your first custom layout using our getting started guide, this article takes you one step further. Here, we break down the core building blocks of the Welcome app’s custom layout system, covering available variables, feature flags, templating syntax, and how to use widgets and components effectively.
Use this guide as your go-to reference when shaping more polished, feature-rich layouts.
Jump to
Handlebars templating
The Welcome app uses Handlebars as its templating engine. This allows you to:
- Insert variable values:
{{variable}}
- Insert unescaped HTML:
{{{variable}}}
- Use conditional logic:
{{#if variable}}...{{else}}...{{/if}}
- Loop through arrays:
{{#each array}}...{{/each}}
- Use custom helpers like audience targeting:
{{#audience "guid"}}...{{/audience}}
Examples:
<!-- Display the username -->
<h1>Hello, {{username}}!</h1>
<!-- Insert an unescaped background URL -->
<div style="background-image: url({{{background}}})"></div>
<!-- Conditional rendering -->
{{#unless custom.greeting.hide}}
<div class="greeting">
<a365widget data-widget="greeting"></a365widget>
</div>
{{/unless}}
<!-- Loop through content items -->
{{#each content}}
<div class="item">
<h2>{{title}}</h2>
<p>{{description}}</p>
</div>
{{/each}}
Variables
The following variables are available for use in your Handlebars templates.
Variable | Type | Description |
webPartId |
string | Unique identifier for the web part instance |
userphoto |
string | URL of the user's profile picture |
username |
string | Display name of the user |
sourceUrl |
Nullable<string> | Source URL if applicable |
email |
string | Email address of the user |
audience |
string[] | Array of audience GUIDs the user belongs to |
background |
Nullable<string> | URL of the background image |
custom |
Record<BuiltInFeatures, Record<string, unknown>> | Custom variables defined in the layout |
content |
Slide[] | Array of content slides to display |
The content
variable is an array of Slide
objects with the following properties:
Property | Type | Description |
id |
string | Unique identifier for the slide |
type |
string | The type of content (from ContentSlide or ContentNews) |
title |
string | The title of the slide |
subtitle |
string | The subtitle or secondary text for the slide |
background |
string | The URL of the background image for the slide |
ctaUrl |
string | Call-to-action URL (link destination when slide is clicked) |
ctaText |
string | Call-to-action text (button or link text) |
altText |
string | Alternative text for the slide image (for accessibility) |
custom |
Record<string, unknown> | Optional custom properties specific to the slide |
Features
Features are enabled via data attributes on the metadata template. Each feature adds specific functionality to your layout:
Feature | Attribute | Description |
Greeting | data-feature-greeting="true" |
Enables personalised greeting functionality |
Time | data-feature-time="true" |
Enables time display functionality |
Weather | data-feature-weather="true" |
Enables weather information functionality |
Search | data-feature-search="true" |
Enables search functionality |
Slides | data-feature-slider="true" |
Enables slides functionality (legacy) |
Content | data-feature-content="true" |
Enables content display (slides + news) |
Background | data-feature-background="true" |
Enables background image functionality |
Widgets and components
Widgets are high-level UI elements that combine multiple components:
<a365widget data-widget="greeting"></a365widget>
<a365widget data-widget="time"></a365widget>
<a365widget data-widget="weather"></a365widget>
<a365widget data-widget="search"></a365widget>
<a365widget data-widget="content"></a365widget>
Components are lower-level UI elements that can be used independently:
<a365component data-component="greeting"></a365component>
<a365component data-component="photo"></a365component>
<a365component data-component="time"></a365component>
Best practices
- Keep only one instance of
<style>
,<script>
, and<section>
tags in the layout - Avoid using HTML IDs; prefer classes instead
- If an ID is necessary, ensure it has a unique postfix, e.g.,
<div id="alert-{{webPartId}}"></div>
- Clean up resources in the
onDispose()
function to avoid memory leaks - Use the
.SCOPE
class token to target elements outside the layout scope - Only enable features that are actually used in the layout
- Use localized labels for better user experience
- Do not try to access or style elements outside of the template scope
- Avoid placing markup outside of template tags