Most SharePoint intranets need a way to surface urgent messages — planned maintenance, system outages, important announcements. The requirement sounds simple: show a prominent banner at the top of the homepage, let the communications team control it without developer involvement, and make it disappear cleanly when there's nothing to say.
The implementation choices matter more than they first appear.
Why PnP Modern Search Over Other Options
When this requirement came up on an existing intranet already running PnP Modern Search, the choice of implementation approach was worth thinking through carefully.
A custom SPFx web part was the obvious alternative — full control, clean component, deployable as a solution package. But for a message banner driven by a list, it's significant overhead. Every change to the card layout requires a developer, a build, and a redeployment. For something as operationally simple as a notification banner, that could be the wrong tool.
A static web part — a text web part or a highlighted content web part — would require a page editor to update the homepage every time a message needed to change. That means giving communications teams edit access to the homepage, or routing every message change through someone who has it. Neither is acceptable in a governed intranet.
SharePoint News is designed for a different content pattern entirely. Pinning a news post to the homepage doesn't give you the visual severity coding, the prominent banner placement, or the clean hide-when-empty behaviour you need for operational messaging.
PnP Modern Search was already deployed on the site. No additional solution packages to deploy, no new dependencies to introduce, no approval process for a new web part. A SharePoint list as the data source, a custom Handlebars template for the rendering, and a KQL query to filter active messages. The communications team gets a familiar list interface to manage messages. The solution is entirely list-driven.
The Design Decisions
List-driven ownership was the primary goal. The MessageBanner list gives the communications team full control — create a new item, set MessageStatus to Active, and the banner appears. Set it to Inactive and it disappears. No page editing, no developer involvement, no deployment process. An optional ExpirationDate column means messages can be set to expire automatically without anyone needing to remember to deactivate them.
Severity levels as a choice column — Low, Medium, High — keeps the editor experience simple while giving the template everything it needs to drive visual differentiation. The choice value flows through a managed property into the Handlebars template, where it sets a data-warning-level attribute on the card container. CSS attribute selectors handle the rest — different border colours, background tints, and badge colours for each level, with no JavaScript required.
Two web parts rather than page context detection for the multilingual requirement. The English homepage has one PnP Search Results web part, the French homepage has another. Both query the same list, but the PNP search results webpart slot mappings differ — the French web part maps its Title slot to the RefinableString mapped from TitleFR, and its Description slot to the RefinableString mapped from DescriptionFR. The Handlebars template is nearly identical on both web parts, with the only difference being the French badge text (Élevé/Moyen/Faible) hardcoded in the French template.
This approach is more explicit and easier to maintain than detecting pageContext.cultureInfo.currentUICultureName in the template. Each web part is independently configured, independently testable, and independently updatable.
External template URL rather than inline Handlebars. The template is stored as an .html file in a Site Assets library (PnP_CustomTemplates/BannerEng.html and BannerFR.html) and referenced via the External Template URL option in the web part. This means template changes can be made in one place — edit the file in Site Assets — without touching the web part configuration on the page. It also means the template has version history through SharePoint's document versioning.
The Gotchas
Managed property mapping and crawl delay. The MessageStatus column needs to be mapped to a RefinableString managed property before it can be used in the KQL query. After creating the list and mapping the property, there's a crawl delay before the property becomes available in PnP Modern Search's slot configuration. Triggering a manual reindex on the list speeds this up, but in SharePoint Online you're still waiting for the next crawl cycle. Plan for this when setting up in a production environment.
The hide when empty pattern. This works in combination with the "Hide this web part if there's nothing to show" toggle in the web part settings. The toggle handles the web part container; the totalItemsCount wrapper handles the template content inside it. Both are needed. The toggle alone leaves an empty container with minimal space on the page. The totalItemsCount wrapper alone still leaves the web part frame visible. Together they produce a clean result — when there are no active messages, the banner takes up minimal space and nothing is visible to the user.
The severity CSS pattern. Setting data-warning-level="{{slot item 'RefinableString101'}}" on the card container and then using CSS attribute selectors ([data-warning-level='High']) to drive the styling is cleaner than using Handlebars conditionals to switch CSS classes. The value from the managed property flows directly into the HTML attribute, and CSS handles everything else. No JavaScript, no class-switching logic in the template.
The Result
A banner that communications teams can manage entirely through a SharePoint list. Messages appear within minutes of being set to Active, disappear when set to Inactive or when the expiration date passes, and render correctly in both English and French without any page editing involved.
The full list schema, slot configuration, and both Handlebars templates are on the example page.