Skip to content

Notifications: Add htmlMessage for opt-in HTML rendering in toasts - #23152

Merged
iOvergaard merged 7 commits into
umbraco:mainfrom
andrejd22:temp/enable-html-in-notifications
Jul 8, 2026
Merged

Notifications: Add htmlMessage for opt-in HTML rendering in toasts#23152
iOvergaard merged 7 commits into
umbraco:mainfrom
andrejd22:temp/enable-html-in-notifications

Conversation

@andrejd22

@andrejd22 andrejd22 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Allows notifications/toasts to render HTML via a new opt-in htmlMessage field, so backend EventMessages can contain clickable links (the original goal of this PR).

How it works

  • UmbNotificationDefaultData.htmlMessage?: string | TemplateResult — takes precedence over message. String values are sanitized (DOMPurify) before rendering; TemplateResults render as-is since Lit escapes their bindings. Mirrors UmbConfirmModalData.content.
  • message keeps its plain-text contract — no behavioural change for existing peek()/stay() call sites or package developers.
  • Backend EventMessages (the umb-notifications header) opt in via the API interceptor and render through umb-peek-error-notification. The plain message is kept markup-free because it is read aloud by the screen-reader announcer.
  • Documented in docs/security.md; unit tests added for both notification layouts.

Why not render all messages as HTML (the original approach): sanitization silently strips angle-bracket plain text (e.g. IEnumerable<T>IEnumerable), and sanitized markup from user-controlled strings (links, images, styled elements) would still render — a phishing/UI-spoofing vector. Making HTML opt-in scopes that trust decision to deliberate call sites.

Testing

  1. Return an EventMessage from the server containing HTML, e.g. <a href="/umbraco">a link</a> → the toast renders a clickable link (scripts/event handlers are stripped).
  2. Existing notifications (save, publish, errors, etc.) render exactly as before.

Taken over and reworked by HQ — thanks @andrejd22 for the contribution and the original implementation!

Copilot AI review requested due to automatic review settings June 17, 2026 13:33
@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown

Hi there @andrejd22, thank you for this contribution! 👍

While we wait for one of the Core Collaborators team to have a look at your work, we wanted to let you know about that we have a checklist for some of the things we will consider during review:

  • It's clear what problem this is solving, there's a connected issue or a description of what the changes do and how to test them
  • The automated tests all pass (see "Checks" tab on this PR)
  • The level of security for this contribution is the same or improved
  • The level of performance for this contribution is the same or improved
  • Avoids creating breaking changes; note that behavioral changes might also be perceived as breaking
  • If this is a new feature, Umbraco HQ provided guidance on the implementation beforehand
  • 💡 The contribution looks original and the contributor is presumably allowed to share it

Don't worry if you got something wrong. We like to think of a pull request as the start of a conversation, we're happy to provide guidance on improving your contribution.

If you realize that you might want to make some changes then you can do that by adding new commits to the branch you created for this work and pushing new commits. They should then automatically show up as updates to this pull request.

Thanks, from your friendly Umbraco GitHub bot 🤖 🙂

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR updates notification rendering to allow HTML content inside toast notifications by using Lit’s unsafeHTML directive.

Changes:

  • Render default notification data.message as HTML via unsafeHTML.
  • Render peek-error notification message as HTML when the message is a string, otherwise render the template as-is.
  • Add unsafeHTML imports in relevant notification elements.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/Umbraco.Web.UI.Client/src/packages/core/notification/layouts/default/notification-layout-default.element.ts Switches default notification message rendering from text interpolation to unsafeHTML.
src/Umbraco.Web.UI.Client/src/packages/core/notification/controllers/peek-error/peek-error-notification.element.ts Uses unsafeHTML for string messages while preserving non-string/template rendering.

@iOvergaard iOvergaard left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea, but we need to sanitize the HTML first. Towards that purpose, you can import the sanitizeHTML function and use that.

import { sanitizeHTML } from '@umbraco-cms/backoffice/utils';

const sanitizedMessage = sanitizeHTML(this.#message);

return unsafeHTML(sanitizedMessage);

@andrejd22

Copy link
Copy Markdown
Contributor Author

@iOvergaard added sanitizeHTML function. Thank you!

@andrejd22
andrejd22 requested a review from iOvergaard June 18, 2026 11:20
iOvergaard and others added 4 commits July 8, 2026 13:25
… HTML

Rendering every notification message as HTML changed the plain-text
contract of UmbNotificationDefaultData.message for all existing callers:
angle-bracket text was silently stripped by sanitization, and sanitized
markup (links, images) from user-controlled strings could still render.

Instead, add an explicit htmlMessage field (string | TemplateResult,
mirroring UmbConfirmModalData.content) that takes precedence over
message. String values are sanitized before rendering; TemplateResults
render as-is since Lit escapes bindings. The backend EventMessage path
opts in via the API interceptor, so server-sent notifications can
contain links. message keeps rendering as plain text everywhere.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The notification container announces data.message via textContent, so
passing the raw EventMessage HTML there would have screen readers read
the literal markup. Extract the text with an inert DOMParser document
(nothing executes or loads) and keep the HTML in htmlMessage only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@iOvergaard iOvergaard changed the title Render HTML in notification layout Backoffice: Support html messages in toasts and render HTML from backend notifications Jul 8, 2026
@iOvergaard iOvergaard changed the title Backoffice: Support html messages in toasts and render HTML from backend notifications Backoffice: Support HTML messages in toasts and render HTML from backend notifications Jul 8, 2026
@iOvergaard
iOvergaard enabled auto-merge (squash) July 8, 2026 11:40
@iOvergaard iOvergaard changed the title Backoffice: Support HTML messages in toasts and render HTML from backend notifications Notifications: Add htmlMessage for opt-in HTML rendering in toasts Jul 8, 2026
@iOvergaard
iOvergaard merged commit 2c4414f into umbraco:main Jul 8, 2026
31 checks passed
@adavidovic92

Copy link
Copy Markdown

@iOvergaard Is it possible to have this in Umbraco v17?

@iOvergaard

Copy link
Copy Markdown
Contributor

Is it possible to have this in Umbraco v17?

It's a new feature, so generally I'd say no. It depends on how stable it is; that is probably the most I can promise at this point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants