Skip to content

Blazor <head> modification using a section-based approach#34218

Merged
MackinnonBuck merged 34 commits into
mainfrom
t-mbuck/html-head-modification
Jul 16, 2021
Merged

Blazor <head> modification using a section-based approach#34218
MackinnonBuck merged 34 commits into
mainfrom
t-mbuck/html-head-modification

Conversation

@MackinnonBuck
Copy link
Copy Markdown
Member

@MackinnonBuck MackinnonBuck commented Jul 8, 2021

Blazor modification via new Sections API
Enables rendering to the HTML component through a new API.

PR Description
Previously, we have explored components that mutate the HTML <head> via JavaScript interop. This created numerous challenges, including handling prerendering and dealing with asynchrony. This PR introduces mechanism for defining a <HeadOutlet> that can be rendered to by a <HeadContent>.

Overview
A <HeadOutlet> is a component whose child content is determined by a <HeadContent> component. We could dynamically render to the <head> from a Counter component as follows:

<!-- Title set via HeadContent -->
<HeadContent>
    <!-- This will replace the child content in the `HeadSection` in HeadRoot.razor -->
    <meta name="description" content="A page with a button clicked @currentCount times">
    <!-- ... -->
</HeadContent>

<!-- Or, if you just want to set the title -->
<PageTitle>@currentCount</PageTitle>

To make HeadRoot render to the head, we can specify it as a root component that renders to the <head>, similar to how root components are generally rendered to to the <body>. Here's how this can be done in Blazor WebAssembly:

// In Program.Main()
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<HeadRoot>("head::after");
builder.RootComponents.Add<App>("app");

When the ::after pseudo-selector is specified, the contents of the root component are appended to the existing head contents instead of replacing them. This allows developers to keep static head content in index.html without having to repeat it in Blazor components.

In Blazor Server, we can take a similar approach by adding a 2nd component tag helper in the <head> in _Host.cshtml.

Addresses #25705

Still lots of work to do, including full prerendering support for Blazor Server.
Comment thread src/Components/Components/src/RenderHandle.cs Outdated
Comment thread src/Components/Components/src/RenderTree/Renderer.cs
Comment thread src/Mvc/Mvc.ViewFeatures/src/Rendering/IPrerenderingDependencyManager.cs Outdated
Comment thread src/Components/Components/src/RenderHandle.cs Outdated
Comment thread src/Components/Web/src/Head/HeadContent.cs Outdated
Comment thread src/Components/Web/src/Head/HeadOutlet.cs Outdated
Comment thread src/Components/Web/src/Sections/SectionRegistry.cs Outdated
Comment thread src/Components/Web/src/Sections/SectionRegistry.cs Outdated
Comment thread src/Components/Web/src/Sections/SectionRegistry.cs Outdated
Comment thread src/Components/Web/src/Sections/SectionRegistry.cs Outdated
Comment thread src/Mvc/Mvc.ViewFeatures/src/Rendering/IPrerenderingDependencyManager.cs Outdated
@MackinnonBuck
Copy link
Copy Markdown
Member Author

@pranavkm IPrerenderingDependencyManager is used in https://github.com/dotnet/aspnetcore/pull/34218/files#diff-68c83ea692cffe3129af37252dcf73c080b875b1a6bb4b50cc8a176a9cbc2ee1R115.

We've identified a possibly cleaner API for this, so I'm investigating a new approach.

Copy link
Copy Markdown
Contributor

@pranavkm pranavkm left a comment

Choose a reason for hiding this comment

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

This looks pretty nice.

Comment thread src/Components/Components/src/Sections/SectionContent.cs Outdated
Comment thread src/Components/Components/src/Sections/SectionOutlet.cs Outdated
Comment thread src/Components/Components/src/Sections/SectionRegistry.cs Outdated
Comment thread src/Components/Components/src/Sections/SectionRegistry.cs
Comment thread src/Components/Web.JS/src/Boot.WebAssembly.ts Outdated
Comment thread src/Components/WebAssembly/WebAssembly/src/Rendering/WebAssemblyRenderer.cs Outdated
Comment thread src/Mvc/Mvc.TagHelpers/src/PrerenderingHelpers.cs Outdated
Comment thread src/Components/test/testassets/TestServer/Pages/PrerenderedHost.cshtml Outdated
Comment thread src/Mvc/Mvc.TagHelpers/src/ComponentOutputTagHelper.cs Outdated
Comment thread src/Mvc/Mvc.TagHelpers/src/ComponentTagHelper.cs Outdated
@MackinnonBuck MackinnonBuck marked this pull request as ready for review July 13, 2021 17:48
Comment thread src/Components/Web/src/Sections/HeadContent.cs Outdated
Comment thread src/Components/Web/src/Sections/HeadSection.cs Outdated
Comment thread src/Components/Web/src/Sections/PageTitle.cs Outdated
Comment thread src/Mvc/Mvc.TagHelpers/src/Resources.resx Outdated
Comment thread src/Components/Web.JS/src/Boot.Server.ts
Comment thread src/Components/WebAssembly/WebAssembly/src/Hosting/RootComponentMapping.cs Outdated
Copy link
Copy Markdown
Member

@SteveSandersonMS SteveSandersonMS left a comment

Choose a reason for hiding this comment

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

Amazing work, @MackinnonBuck! This is a great feature. I know it's involved a lot of design but I think the end result is really superb and solves a lot of problems at once.

I posted a few other comments and suggestions but I think you should feel free to merge once they are handled to your satisfaction.

Comment thread src/Components/Samples/BlazorServerApp/App.razor
Comment thread src/Components/Web.JS/src/Rendering/Renderer.ts Outdated
@MackinnonBuck MackinnonBuck enabled auto-merge (squash) July 16, 2021 21:07
@MackinnonBuck MackinnonBuck disabled auto-merge July 16, 2021 21:11
@MackinnonBuck MackinnonBuck enabled auto-merge (squash) July 16, 2021 21:28
@MackinnonBuck MackinnonBuck merged commit 30f0857 into main Jul 16, 2021
@MackinnonBuck MackinnonBuck deleted the t-mbuck/html-head-modification branch July 16, 2021 22:46
@ghost ghost added this to the 6.0-rc1 milestone Jul 16, 2021
mkArtakMSFT pushed a commit that referenced this pull request Jul 20, 2021
…34518)

## Description

This PR introduces a way for developers to modify the HTML `<head>` contents from Blazor.

## Customer Impact

With this feature, customers will be able to easily
* Modify the document title (tab name).
* Add link previews for links to their web app.
* Optimize their website for SEO.
* Dynamically change style sheets (e.g. switch between light and dark modes).

Other SPA frameworks have third-party libraries enabling `<head>` modification, so this change makes Blazor an even more viable alternative.


Addresses #25705
@IEvangelist
Copy link
Copy Markdown
Member

Hi @MackinnonBuck, is this feature (i.e.; components and capabilities) supposed to be available in .NET 6.0.100-preview.6.21355.2? I cannot seem to get it to work in my Blazor WebAssembly app.

@ghost
Copy link
Copy Markdown

ghost commented Jul 27, 2021

Hi @IEvangelist. It looks like you just commented on a closed PR. The team will most probably miss it. If you'd like to bring something important up to their attention, consider filing a new issue and add enough details to build context.

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

Labels

area-blazor Includes: Blazor, Razor Components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants