Skip to content
  • There are no suggestions because the search field is empty.

Custom layout: Advanced functionality explained

A detailed guide to advanced functionality, including custom variables and audience targeting, available in custom layouts

If you’re ready to go beyond the core templating features of Welcome, this article covers the advanced tools available to custom layout developers. You’ll learn how to use dynamic metadata from SharePoint, set up audience targeting, hook into layout lifecycle events, and safely apply scoped styling using .SCOPE.

This guide is ideal for those building polished, flexible, and dynamic layouts for the Welcome app.

Jump to


Settings and custom managed metadata fields

The <settings> section allows you to define custom settings for your layout, including custom managed metadata fields that will be loaded for dynamic content.

Basic structure:

<settings>
<content>
<fields>
<field name="FieldName1" />
<field name="FieldName2" />
</fields>
</content>
</settings>

Custom managed metadata fields

Custom managed metadata fields allow you to load additional metadata from SharePoint lists or libraries where your content is stored. These fields should be mapped to a tenant-scoped managed property.

We recommend reading the following Microsoft resources before proceeding:

How to define custom fields

  1. Add a <field> element inside the <fields> section
  2. Set the name attribute to the internal name of the SharePoint managed property

Example:

<settings>
<content>
<fields>
<field name="ShowInWelcome" />
<field name="Category" />
<field name="Priority" />
</fields>
</content>
</settings>

Accessing custom fields in layouts

Custom fields can be accessed in the layout using the content[i].custom object:

{{#each content}}
{{#if custom.ShowInWelcome}}
<div class="item">
<h3>{{title}}</h3>
{{#if custom.Category}}
<span class="category">Category: {{custom.Category}}</span>
{{/if}}
{{#if custom.Priority}}
<span class="priority priority-{{custom.Priority}}">{{custom.Priority}}</span>
{{/if}}
</div>
{{/if}}
{{/each}}

Note: custom managed metadata fields are only supported for dynamic content (news and pages) loaded from SharePoint. They are not supported for static content defined directly in the web part settings.

Common use cases

  • Filtering content: Show only items with specific metadata values
  • Styling content: Apply different styles based on metadata
  • Categorizing content: Group or organize content by metadata values
  • Adding badges or tags: Display additional visual indicators based on metadata

Advanced example

{{#each content}}
{{#if custom.ShowInWelcome}}
<div class="card {{#if custom.IsHighlighted}}highlighted{{/if}}">
<h3>{{title}}</h3>

{{#if custom.Categories}}
<div class="categories">
{{#each custom.Categories}}
<span class="tag">{{this.label}}</span>
{{/each}}
</div>
{{/if}}

{{#if custom.Expires}}
<div class="expires-on">Expires: {{formatDate custom.Expires "MM/DD/YYYY"}}</div>
{{/if}}

{{#if custom.Owner}}
<div class="owner">
<img src="{{custom.Owner.pictureUrl}}" alt="{{custom.Owner.displayName}}" />
<span>{{custom.Owner.displayName}}</span>
</div>
{{/if}}
</div>
{{/if}}
{{/each}}

Custom variables

The custom variable is organized by feature and contains user-defined settings:

Path Description Example Access
custom.greeting.* Variables related to the greeting feature {{custom.greeting.hide}}
custom.time.* Variables related to the time feature {{custom.time.hide}}
custom.weather.* Variables related to the weather feature {{custom.weather.hide}}
custom.search.* Variables related to the search feature {{custom.search.hide}}
custom.content.* Variables related to the content feature {{custom.content.heading}}, {{custom.content.cycle}}
custom.background.* Variables related to the background feature {{custom.background.title}}

Audience targeting

To specify which audiences to load, you must list them in a settings metadata section:

<settings>
    <content>
        <fields>
            <field name="WelcomeNewsCategory" />
        </fields>
    </content>
    <!--
                    List any audiences ids you want to use in your template. These ids then can be used with {{#audience "<guid>"}} helper.
                -->
    <audiences>
        <audience id="54698842-c8c0-4c95-9832-b88a52065ab3" />
    </audiences>
</settings>

 

You can conditionally render content based on audience targeting using Handlebars helpers:

{{#audience "00000000-0000-0000-0000-000000000000"}}
<div>Content for audience 1</div>
{{else}}
{{#audience "11111111-1111-1111-1111-111111111111"}}
<div>Content for audience 2</div>
{{else}}
<div>Default content</div>
{{/audience}}
{{/audience}}

You can also use variables for dynamic audience targeting:

{{#audience custom.content.secret}}
<div>This content is only visible to the specified audience</div>
{{/audience}}

Lifecycle hooks

Three JavaScript functions can be defined to hook into the layout's lifecycle:

1. onInitialize()

Called when the layout is initialized

function onInitialize() {
console.log('Layout initialized');
// Set up resources, event listeners, etc.

var webPart = ctx.getWebPart(); // get web part context

// Example: Make a SharePoint REST API call
webPart.spHttpClient.get(
webPart.pageContext.web.absoluteUrl + '/_api/web?$select=Title',
webPart.spHttpClient.constructor.configurations.v1,
{ headers: { 'Accept': 'application/json' } }
)
.then(function(response) {
return response.json();
})
.then(function(data) {
console.log('Web Title:', data.Title);
})
.catch(function(error) {
console.error('Error:', error);
});
}

2. onError(error)

Called when an error occurs

function onError(error) {
console.error('Layout error:', error);
// Handle errors
}

3. onDispose()

Called when the layout is disposed

function onDispose() {
console.log('Layout disposed');
// Clean up resources, remove event listeners, etc.
clearInterval(interval); // example: clean up interval
}

JavaScript context

A global ctx object is available in your scripts to interact with the Welcome app:

// Get a custom variable value
var hideTime = ctx.getVariable('custom.time.hide');

// Access the web part context
var webPart = ctx.getWebPart();

// Make SharePoint API calls
webPart.spHttpClient.get(
webPart.pageContext.web.absoluteUrl + '/_api/web',
webPart.spHttpClient.constructor.configurations.v1,
{ headers: { 'Accept': 'application/json' } }
)
.then(response => response.json())
.then(data => console.log('Web Title:', data.Title))
.catch(error => console.error('Error:', error));

Understanding the .SCOPE pseudo-class

The .SCOPE pseudo-class is a special selector in Welcome app layouts that gets replaced at runtime with the actual scope of the web part instance (e.g., #acc365-Welcome-12345). This provides several benefits:

  • CSS Isolation: Ensures your styles don't affect other elements on the page
  • CSS Variables: Define CSS variables that are scoped only to your web part
  • External Targeting: Safely target elements outside your layout when necessary
  • Prevent Collisions: Avoid CSS class name collisions with other components

When the layout is rendered, .SCOPE is replaced with the actual web part container selector, turning:

.SCOPE { --primary-color: #0078d4; }

into something like:

#acc365-Welcome-12345 { --primary-color: #0078d4; }

This allows you to safely define styles that won't interfere with other elements on the page, even if they use the same class names.


⬅️Back: Custom layout: Core functionality explained