Skip to content

Influencing HTML Head from a Blazor component #10450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
danroth27 opened this issue May 22, 2019 · 20 comments
Closed

Influencing HTML Head from a Blazor component #10450

danroth27 opened this issue May 22, 2019 · 20 comments
Assignees
Labels
area-blazor Includes: Blazor, Razor Components Components Big Rock This issue tracks a big effort which can span multiple issues Done This issue has been fixed enhancement This issue represents an ask for new feature or an enhancement to an existing one

Comments

@danroth27
Copy link
Member

In Blazor apps the root of the HTML document is typically controlled by the layout component. If other components need to influence the contents of the HTML Head tag (e.g. to add or change Meta or Title tags) there isn't really an established patterns to do that today.

@danroth27 danroth27 added area-blazor Includes: Blazor, Razor Components Needs: Design This issue requires design work before implementating. labels May 22, 2019
@mkArtakMSFT mkArtakMSFT added this to the 3.0.0-preview8 milestone May 22, 2019
@mkArtakMSFT mkArtakMSFT modified the milestones: 3.0.0-preview8, 3.1.0 May 23, 2019
@Andrzej-W
Copy link

Hopefully it will work during prerendering in Blazor client side app. It is needed for SEO and social sites integration.

@roduman
Copy link

roduman commented Aug 9, 2019

Very lacking this functionality today

@vertonghenb
Copy link
Contributor

vertonghenb commented Aug 19, 2019

Sometimes it's even needed to adjust the <body> tag (most of the time the css classes due to theme requirements. For example the case where you open/close sidebars and it's based on the css class of the body tag. Currently I use the following code snipped to do so via Interop:

window.application = {
    toggleAsideOnMobile() {
        const className = 'kt-aside--on';
        const body = document.getElementsByTagName('body')[0];
        const aside = document.getElementById('kt_aside');
        body.classList.toggle(className);
        aside.classList.toggle(className);
        return true;
    },
    toggleTopbarOnMobile() {
        const className = 'kt-header__topbar--mobile-on';
        const body = document.getElementsByTagName('body')[0];
        body.classList.toggle(className);
        return true;
    }
};

@chucker
Copy link

chucker commented Aug 19, 2019

@vertonghenb unless it has to be the <body> tag, you don't need JS for that. Inside the components, you can simply emit different CSS classes.

Blazor doesn't have built-in tooling for that, but you can use something like CssBuilder.

@vertonghenb
Copy link
Contributor

@chucker Yes, I know but it has to be the body tag.

@TrabacchinLuigi
Copy link

TrabacchinLuigi commented Sep 12, 2019

I stumbled upon this today, what I really need is the ability to write in the browser history, and I guess it simply takes to add some parameters to what already exist, the layout of the page can inspect the route and generate SEO metadata during load... It still is in a MVC controller after all...

I suspect SEO engines just do a lot of requests without using JavaScript so... I don't see how that is useful, here a workaround for those who want per request page title or meta

File: _Host.cshtml

@page "/"
@namespace MyWebApp.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@inject Data.ApplicationDbContext  ApplicationDbContext

@{
    var seoEntity = ApplicationDbContext.ExampleSeoTable
        .SingleOrDefault(x => x.path == this.HttpContext.Request.Path);
    var title = seoEntity?.Title ?? "This page have no title in the db";
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@title</title>
    <base href="~/" />
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
    <link href="css/site.css" rel="stylesheet" />
</head>
...
</html>

@TrabacchinLuigi
Copy link

@vertonghenb I don't see why anything need to be modified to achieve what you ask :

File _Host.cshtml

<!DOCTYPE html>
<html lang="en">
...
</head>
@(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
</html>

Then

File App.razor

@code { ... }
<body class="@someClasses">
<Router AppAssembly="@typeof(Program).Assembly">
...
</Router>
</body>

@vertonghenb
Copy link
Contributor

@TrabacchinLuigi I don’t know that was possible, awesome! Thanks for sharing!

@dotkiwi
Copy link

dotkiwi commented Sep 13, 2019

@TrabacchinLuigi Hmm, I'm not sure if this would work, please correct me if I'm wrong. Since components can't contain <script> tags, if you place the <body> tag inside a component then you have nowhere to place <script> tags. <script> tags are meant to be in the <body> are they not?

@vertonghenb
Copy link
Contributor

@TrabacchinLuigi Hmm, I'm not sure if this would work, please correct me if I'm wrong. Since components can't contain <script> tags, if you place the <body> tag inside a component then you have nowhere to place <script> tags. <script> tags are meant to be in the <body> are they not?

That's a good argument!

@TrabacchinLuigi
Copy link

TrabacchinLuigi commented Sep 14, 2019

@dotkiwi @vertonghenb as far as i know script tags can be placed in head tag, inside body tag or after it, it just depends on when you want that script to be available and start executing (also how bad is that script, the trend of putting scripts at the end of the page started because of people writing bad libs not tied to events, and by doing so the scripts worked only if they where "rendered by the browser" after the rest of the dom), in this case it should not matter, the page is very lightweight and the majority of the content is downloaded later by Blazor ...

@zachneu
Copy link

zachneu commented Mar 1, 2020

Is there anyway now to add script and css references from a Razor component now? I have several Razor components with their own JavaScript files and css files. If i use these components i'll have to link to their JavaScript and css files in "index.html" manually. Is there some way this can be done from the Razor component?

@DamianEdwards
Copy link
Member

Another use case to document that the lack of this feature is impacting right now is web analytics solutions. Today, in systems like Application Insights, page views are tracked via the JavaScript SDK which can be configured to auto-track route changes and report those as page views (no problem there). The issue is the document title is used as the page view name, so looking at page views in your analytics dashboard just shows all views being for the application home page (as the title never changes).

@muratgur
Copy link

muratgur commented May 3, 2020

Is there anyway now to add script and CSS references from a Razor component now? I have several Razor components with their own JavaScript files and css files. If i use these components i'll have to link to their JavaScript and css files in "index.html" manually. Is there some way this can be done from the Razor component?

This is a very reasonable request. How can I add style links inside a component? FAQ page needs custom style for example. The Head tag is in _Host.cshtml and as far as I understand there is no way right now?

@dodyg
Copy link

dodyg commented May 26, 2020

This feature will be very useful in supporting RTL and LTR layout switching.

@walterlv
Copy link

@GioviQ I've tried this component.

But this only works in the Browser and we can find that the title changes in the browser's tab. But the title WILL NOT UPDATE if someone tries to share a link through some social apps, because the title is updated using the Web Socket but the social apps only fetch the title once and will not update further.

@GioviQ
Copy link

GioviQ commented May 27, 2020

@walterlv I think you're right, so what is the solution?

@SPWwj
Copy link

SPWwj commented Jun 2, 2020

need a way for server to render prerender component base on first time request url. this will help seo to fetch necessary info, meanwhile allow user to serve the seamlessly

@pranavkm pranavkm removed Needs: Design This issue requires design work before implementating. PRI: 1 - Required labels Jun 15, 2020
@EffectivelyEfficient
Copy link

To add to the example by @vertonghenb and when using MapFallbackToPage, the _Host.cshtml file is evaluated, then if present, the cshtml layout file is evaluated. In addition, a dependency injected service can be accessed by the blazor ServerPrerendered, and the layout page.

So to influence the HTML Head when using ServerPrerendered, you make sure you are constructing the HTML Head in a cshtml layout file. You then use a transient dependency injected service to carry the value from Blazor to the layout.

@vertonghenb I don't see why anything need to be modified to achieve what you ask :

File _Host.cshtml

<!DOCTYPE html>
<html lang="en">
...
</head>
@(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
</html>

Then

File App.razor

@code { ... }
<body class="@someClasses">
<Router AppAssembly="@typeof(Program).Assembly">
...
</Router>
</body>

@pranavkm pranavkm assigned MackinnonBuck and unassigned javiercn Jun 24, 2020
@MackinnonBuck MackinnonBuck added Done This issue has been fixed and removed Working labels Jul 23, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Aug 22, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components Components Big Rock This issue tracks a big effort which can span multiple issues Done This issue has been fixed enhancement This issue represents an ask for new feature or an enhancement to an existing one
Projects
None yet
Development

No branches or pull requests