Skip to content

🐛 BUG: Collection of <head> issues as of v0.21.10 #2128

@philipp-tailor

Description

@philipp-tailor

What version of astro are you using?

0.21.10

Describe the Bug

I am aware about the head RFC, and the linked GitHub issues. I still felt that a complete overview over current behaviors is missing for people dealing with <head/> related issues.
These variations below are my most relevant attempts to create a structure to manage composite, dynamic head content in a project with nested layouts. Some of the variations - in my opinion - should work. Others of them I didn't expect to work, and they indeed did not. But that none of them work is a deal breaker for my use-cases. Behaviors changed in a breaking manner from v0.20.x to v0.21.x without mention in the changelog, but it appeared to me that they even changed between different v0.21.x patch versions (I might be wrong about that). The variations of unexpected / non-working behaviors described below reflect the state as of v0.21.10.
With this issue I hope to raise awareness for (potential) users of astro, and show up variations of possible cases the RFC, astro, and the test suite could cover. This overview is probably incomplete - feel free to document more behaviors as you detect them below.

1. Head cant't be complemented with content passed in fragment to slot in head

<!-- components/BaseHead.astro -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<meta name="color-scheme" content="light dark">
<!--layouts/BaseLayout.astro-->
<head>
	<BaseHead />
	<slot name="head"/>
</head>
<!-- layouts/TopPageLayout.astro-->
<BaseLayout>
	<Fragment slot="head">
		<meta property="og:type" content="article" />
		<link rel="stylesheet" href="/article.css" />
	</Fragment>
</BaseLayout>

Expected:

<!-- Build output of page using `layouts/TopPageLayout.astro` -->
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
	<meta property="og:type" content="article" />
	<link rel="stylesheet" href="/article.css" />
</head>
<body>...</body>

Actual:

<!-- Build output of page using `layouts/TopPageLayout.astro` -->
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
</head>
<body>
	<meta property="og:type" content="article" />
	<link rel="stylesheet" href="/article.css" />
</body>

2. Head cant't be complemented with head element passed to slot in head

This is a variation of 1., which doesn't make much sense if astro is to mirror HTML, since there can only be one head in the HTML output. However, I hoped it might lead the compiler to detect that the content passed to the head slot shall be attached to the head. It doesn't, and instead behaves the same as 1..

<!-- components/BaseHead.astro -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<meta name="color-scheme" content="light dark">
<!--layouts/BaseLayout.astro-->
<head>
	<BaseHead />
	<slot name="head"/>
</head>
<!-- layouts/TopPageLayout.astro-->
<BaseLayout>
	<head slot="head">
		<meta property="og:type" content="article" />
		<link rel="stylesheet" href="/article.css" />
	</head>
</BaseLayout>

Expected:

<!-- Build output of page using `layouts/TopPageLayout.astro` -->
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
	<meta property="og:type" content="article" />
	<link rel="stylesheet" href="/article.css" />
</head>
<body>...</body>

Actual:

<!-- Build output of page using `layouts/TopPageLayout.astro` -->
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
</head>
<body>
	<meta property="og:type" content="article" />
	<link rel="stylesheet" href="/article.css" />
</body>

3. Head content is rendered in body when head is set as default slot content

I am not sure if this is a variation of this issue?

<!-- components/BaseHead.astro -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<meta name="color-scheme" content="light dark">
<!--layouts/BaseLayout.astro-->
<slot name="head">
	<head>
		<BaseHead />
	</head>
</slot>
<!-- layouts/TopPageLayout.astro-->
<BaseLayout/>

Expected:

<!-- Build output of page using `layouts/TopPageLayout.astro` -->
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
</head>
<body>...</body>

Actual:

<!-- Build output of page using `layouts/TopPageLayout.astro` -->
<head></head>
<body>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
</body>

4. Head can't be set when passed as slot

This expands upon 3., and I include it to show what I expected to happen if content is passed to the head slot.

<!-- components/BaseHead.astro -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<meta name="color-scheme" content="light dark">
<!--layouts/BaseLayout.astro-->
<slot name="head">
	<head>
		<BaseHead />
	</head>
</slot>
<!-- layouts/TopPageLayout.astro-->
<BaseLayout>
	<head slot="head">
		<BaseHead />
		<meta property="og:type" content="article" />
	</head>
</BaseLayout>

Expected:

<!-- Build output of page using `layouts/TopPageLayout.astro` -->
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
	<meta property="og:type" content="article" />
</head>
<body>...</body>

Actual:

<!-- Build output of page using `layouts/TopPageLayout.astro` -->
<head></head>
<body>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
	<meta property="og:type" content="article" />
</body>

5. Multiple heads rendered in different layouts are not compositing

Again, a case that does not make sense from HTML perspective, but in depsparation, I tried whether it would work nevertheless.

<!-- components/BaseHead.astro -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<meta name="color-scheme" content="light dark">
<!--layouts/BaseLayout.astro-->
<head>
	<BaseHead />
</head>
<!-- layouts/TopPageLayout.astro-->
<BaseLayout>
	<head>
		<meta property="og:type" content="article" />
	</head>
</BaseLayout>

Expected:

<!-- Build output of page using `layouts/TopPageLayout.astro` -->
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
	<meta property="og:type" content="article" />
</head>
<body>...</body>

Actual:

<!-- Build output of page using `layouts/TopPageLayout.astro` -->
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
</head>
<body>
	<meta property="og:type" content="article" />
</body>

6. Head can't be included only by rendering component rendering head

This one has already been reported. The code below does not use nested layouts, and does not have dynamic parts to it. That this simple case does not work, excludes all application structures where different layouts render <BaseHead.astro with dynamic head content passed to the slots.

<!-- components/BaseHead.astro -->
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
	<slot/>
</head>
<!--layouts/BaseLayout.astro-->
<BaseHead />

Expected:

<!-- Build output of page using `layouts/BaseLayout.astro` -->
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
</head>
<body>...</body>

Actual:

<!-- Build output of page using `layouts/BaseLayout.astro` -->
<body>...</body>

7. Head set from svelte components hydrated on client load is not part of build output

Another, advanced case that does not work, is including content from svelte components with <svelte:head> in the static build output. I assume that it's extremely difficult for astro to detect if a svelte component is always rendered and hydrated in a layout with client:load, and always limited to only being changed from the svelte component when its bundled JS is being executed?

<!-- components/BaseHead.svelte -->
<svelte:head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
	<slot/>
</svelte:head>
<!--layouts/BaseLayout.astro-->
<BaseHead client:load />

Expected:

<!-- Build output of page using `layouts/BaseLayout.astro` -->
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width,initial-scale=1.0" />
	<meta name="color-scheme" content="light dark">
</head>
<body>...</body>

Actual:

<!-- Build output of page using `layouts/BaseLayout.astro` -->
<body>...</body>

The head then changes once BaseHead.svelte is hyrated on the client.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions