-
Notifications
You must be signed in to change notification settings - Fork 361
docs(solid-meta): add useHead reference #1387
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
Changes from 2 commits
958cf54
acda4b1
73262c6
2652d3c
465fa97
92e7aba
878cf12
56c8a26
55b7128
57046e0
468d66f
dc45010
f1dfcaa
eca5bc1
80437b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |
| "meta.mdx", | ||
| "style.mdx", | ||
| "base.mdx", | ||
| "metaprovider.mdx" | ||
| "metaprovider.mdx", | ||
| "use-head.mdx" | ||
| ] | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,247 @@ | ||
| --- | ||
| title: useHead | ||
| order: 7 | ||
| use_cases: >- | ||
| custom head tags, scripts, json-ld, arbitrary head elements, dynamic metadata, | ||
| ssr head management | ||
| tags: | ||
| - usehead | ||
| - head | ||
| - meta | ||
| - script | ||
| - json-ld | ||
| - ssr | ||
| version: '1.0' | ||
| description: >- | ||
| useHead inserts custom elements into document head with fine-grained control, | ||
| including scripts and JSON-LD, while staying SSR-ready. | ||
| --- | ||
|
|
||
| `useHead` registers a custom head tag with the nearest [`MetaProvider`](/solid-meta/reference/meta/metaprovider). | ||
| It is the low-level API used by the head components. | ||
| It must be called under a `MetaProvider`, or it throws. | ||
|
|
||
| Use it when you need a tag that does not have a dedicated component or when you need full control over closing tags and escaping. | ||
|
|
||
| ## When to use useHead | ||
|
|
||
| - Insert tags without built-in components, such as `script` and `noscript`. | ||
| - Control SSR output with `setting.close` and `setting.escape`. | ||
| - Inject per-page structured data like JSON-LD. | ||
| - Reuse an existing element via `ref`. | ||
|
|
||
| ## Prefer components when possible | ||
|
|
||
| Use the dedicated components when they fit your use case: | ||
|
|
||
| - [`<Title />`](/solid-meta/reference/meta/title) for page titles. | ||
| - [`<Meta />`](/solid-meta/reference/meta/meta) for metadata. | ||
| - [`<Link />`](/solid-meta/reference/meta/link) for external resources. | ||
| - [`<Style />`](/solid-meta/reference/meta/style) for inline styles. | ||
| - [`<Base />`](/solid-meta/reference/meta/base) for base URLs. | ||
|
|
||
| They provide clearer intent and sensible defaults. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We generally try to avoid explanations in the reference section, since its goal is to document the API surface as clearly and directly as possible. We generally try to avoid explanations in the reference section, since its goal is to document the API surface as clearly and directly as possible. Keeping references concise makes them easier to scan and helps readers quickly understand what exists and how it’s shaped, without additional narrative getting in the way. With that in mind, do you mind removing these sections?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the feedback! Sure, I can remove those sections. |
||
|
|
||
| ## Import | ||
|
|
||
| ```ts | ||
| import { useHead } from "@solidjs/meta"; | ||
| ``` | ||
|
|
||
| ## Type | ||
|
|
||
| ```ts | ||
| type TagDescription = { | ||
| tag: string; | ||
| props: Record<string, unknown>; | ||
| setting?: { | ||
| close?: boolean; | ||
| escape?: boolean; | ||
| }; | ||
| id: string; | ||
| name?: string; | ||
| ref?: Element; | ||
| }; | ||
|
|
||
| function useHead(tag: TagDescription): void; | ||
| ``` | ||
|
|
||
| ## Parameters | ||
|
|
||
| ### `tag` | ||
|
|
||
| - **Type:** `string` | ||
| - **Required:** Yes | ||
|
|
||
| The tag name to render in `<head>`, such as `script`, `meta`, or `title`. | ||
|
everton-dgn marked this conversation as resolved.
Outdated
|
||
|
|
||
| ### `props` | ||
|
|
||
| - **Type:** `Record<string, unknown>` | ||
| - **Required:** Yes | ||
|
|
||
| The attributes and properties applied to the element. | ||
|
|
||
| #### `props.children` | ||
|
|
||
| When provided, `children` becomes the element content for tags like `title`, `style`, or `script`. | ||
| On the server, arrays of strings are concatenated without commas. | ||
| If `setting.close` is not enabled, `children` is not rendered during SSR. | ||
|
everton-dgn marked this conversation as resolved.
Outdated
|
||
|
|
||
| ### `setting` | ||
|
|
||
| - **Type:** `{ close?: boolean; escape?: boolean }` | ||
| - **Required:** No | ||
|
|
||
| SSR-only rendering options for the tag contents. | ||
|
|
||
| #### `setting.close` | ||
|
|
||
| - **Type:** `boolean` | ||
| - **Required:** No | ||
|
|
||
| When `true`, the server renders a closing tag and includes `children`. | ||
| Use this for tags that cannot be self-closing, such as `script`, `style`, and `title`. | ||
|
everton-dgn marked this conversation as resolved.
Outdated
|
||
|
|
||
| #### `setting.escape` | ||
|
|
||
| - **Type:** `boolean` | ||
| - **Required:** No | ||
|
|
||
| When `true`, the server HTML-escapes `children`. | ||
| If omitted or `false`, `children` is rendered as raw HTML. | ||
|
everton-dgn marked this conversation as resolved.
Outdated
|
||
|
|
||
| ### `id` | ||
|
|
||
| - **Type:** `string` | ||
| - **Required:** Yes | ||
|
|
||
| A stable identifier used to match server-rendered tags during hydration. | ||
| Use a consistent `id` for the lifetime of the component. | ||
|
everton-dgn marked this conversation as resolved.
Outdated
|
||
|
|
||
| ### `name` | ||
|
|
||
| - **Type:** `string` | ||
| - **Required:** No | ||
|
|
||
| An optional label for the tag. | ||
| For `meta` tags, it typically mirrors `props.name` or `props.property`. | ||
|
everton-dgn marked this conversation as resolved.
Outdated
|
||
|
|
||
| ### `ref` | ||
|
|
||
| - **Type:** `Element` | ||
| - **Required:** No | ||
|
|
||
| An existing element to reuse instead of creating a new one. | ||
| This is usually managed internally. | ||
|
everton-dgn marked this conversation as resolved.
Outdated
|
||
|
|
||
| ## Return value | ||
|
|
||
| `useHead` does not return a value. | ||
|
|
||
| ## Usage | ||
|
everton-dgn marked this conversation as resolved.
Outdated
|
||
|
|
||
| ### Simple custom tag | ||
|
|
||
| ```tsx | ||
| import { useHead } from "@solidjs/meta"; | ||
|
|
||
| useHead({ | ||
| tag: "link", | ||
| id: "rss-feed", | ||
| props: { | ||
| rel: "alternate", | ||
| type: "application/rss+xml", | ||
| title: "Solid RSS", | ||
| href: "/rss.xml", | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| ### JSON-LD per page (script with `close` and `escape`) | ||
|
|
||
| ```tsx | ||
| import { useHead } from "@solidjs/meta"; | ||
|
|
||
| const jsonLD = JSON.stringify({ | ||
| "@context": "https://schema.org", | ||
| "@type": "WebSite", | ||
| name: "Solid Docs", | ||
| url: "https://docs.solidjs.com/", | ||
| }); | ||
|
|
||
| useHead({ | ||
| tag: "script", | ||
| setting: { close: true, escape: false }, | ||
| id: "schema-home", | ||
| props: { | ||
| type: "application/ld+json", | ||
| children: jsonLD, | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| ### Reactive updates | ||
|
|
||
| ```tsx | ||
| import { createSignal } from "solid-js"; | ||
| import { useHead } from "@solidjs/meta"; | ||
|
|
||
| const [pageTitle, setPageTitle] = createSignal("Getting started"); | ||
|
|
||
| useHead({ | ||
| tag: "title", | ||
| setting: { close: true, escape: true }, | ||
| id: "page-title", | ||
| props: { | ||
| get children() { | ||
| return `${pageTitle()} | Solid`; | ||
| }, | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| ## Notes | ||
|
|
||
| ### SSR and hydration | ||
|
|
||
| On the server, tags are collected and rendered into `<head>`. | ||
| During hydration, tags with matching `id` values are reused. | ||
| On client-only renders, existing server tags are removed and replaced. | ||
|
|
||
| ### Dedupe and idempotency | ||
|
|
||
| For `title` and `meta`, only the most recent tag with the same key is kept. | ||
| The key is derived from the tag name and selected attributes. | ||
| For `meta`, the key uses `name` (or `property`), `http-equiv`, `content`, `charset`, and `media`. | ||
| For `title`, the key does not include any attributes. | ||
| Other tag types are not deduped. | ||
| The `id` does not control deduping. | ||
| It ensures hydration can reuse the same element instead of inserting a duplicate. | ||
|
|
||
| ### Reactive updates and cleanup | ||
|
|
||
| `useHead` runs inside a render effect. | ||
| If your tag description reads reactive values, the tag updates when those values change. | ||
| When the component unmounts, the tag is removed and any previous cascading tag is restored. | ||
|
|
||
| ### Security and escaping | ||
|
|
||
| Use `setting.escape: true` when inserting untrusted content. | ||
| Setting `escape: false` renders raw HTML and can create XSS risks. | ||
| Only use `escape: false` with trusted, pre-serialized strings such as JSON-LD. | ||
|
|
||
| ### Best practices | ||
|
|
||
| Use stable, unique `id` values to avoid duplicates. | ||
| Prefer the dedicated head components when they meet your needs. | ||
| Avoid inserting multiple tags that represent the same metadata unless you intend to override. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to the comment above, we want to avoid adding any of these explanation points to the page.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you so much for your help and the detailed feedback on the PR, it was extremely helpful. I believe I’ve incorporated all the feedback into the code. When you have a chance, could you please review the latest changes? |
||
|
|
||
| ## Related | ||
|
|
||
| - [`<MetaProvider />`](/solid-meta/reference/meta/metaprovider) | ||
| - [`<Title />`](/solid-meta/reference/meta/title) | ||
| - [`<Meta />`](/solid-meta/reference/meta/meta) | ||
| - [`<Link />`](/solid-meta/reference/meta/link) | ||
| - [`<Style />`](/solid-meta/reference/meta/style) | ||
| - [`<Base />`](/solid-meta/reference/meta/base) | ||
Uh oh!
There was an error while loading. Please reload this page.