Typed utilities for defining, validating and building best-practice document <head>'s.
Status: Pre-release Please report any issues π Made possible by my Sponsor Program π Follow me @harlan_zw π¦ β’ Join Discord for help |
- π Fully typed Head, ReactiveHead with MDN docs
- π 100+ typed meta's
- π Reactive Vue schema with computed getter support
- π Validation and schema parsing provided by Zod
- π§ Resolve flat meta tags and back again
unpackMeta
packMeta
- β¨ SEO inferring to generate minimal tags with maximum SEO
buildSeoHead
- π£ Title template support
renderTitle
- βοΈ Output to HTML
generateHtml
- π³ Composable, tree-shakable and tiny (< 1kb, see export-size-report)
Typescript base schema for document <head>. Only ships types for easy access to type augmentation.
export interface Head<E extends MergeHead = MergeHead> {
title?: string
titleTemplate?: string | ((title?: string) => string)
base?: Partial<Merge<E['base'], Base>>
link?: (Link & UnsafeKeys & Default<E['link']>)[]
meta?: (Meta & UnsafeKeys & Default<E['meta']>)[]
style?: (Style & UnsafeKeys & Default<E['style']>)[]
script?: (Script & UnsafeKeys & Default<E['script']>)[]
noscript?: (Noscript & UnsafeKeys & Default<E['noscript']>)[]
htmlAttrs?: (HtmlAttributes & UnsafeKeys & Default<E['htmlAttrs']>)
bodyAttrs?: (BodyAttributes & UnsafeKeys & Default<E['bodyAttrs']>)
}
Typescript schema for document <head> with Vue reactivity.
export interface ReactiveHead<E extends MergeHead = MergeHead> {
title?: MaybeRef<Head<E>['title']>
titleTemplate?: Head<E>['titleTemplate'] | Ref<string>
base?: Head<E>['base'] | MaybeRef<MaybeRefObject<Head<E>['base']>>
link?: Head<E>['link'] | ReffableArrayEntries<Head<E>['link']>
meta?: Head<E>['meta'] | ReffableArrayEntries<Head<E>['meta']>
style?: Head<E>['style'] | ReffableArrayEntries<Head<E>['style']>
script?: Head<E>['script'] | ReffableArrayEntries<Head<E>['script']>
noscript?: Head<E>['noscript'] | ReffableArrayEntries<Head<E>['noscript']>
htmlAttrs?: MaybeRef<MaybeRefObject<Head<E>['htmlAttrs']>>
bodyAttrs?: MaybeRef<MaybeRefObject<Head<E>['bodyAttrs']>>
}
Zod schema for validating and parsing head tags.
Vue bindings for handling deep reactive Ref
and Computed
head tags.
See below
npm install --save-dev zhead
# Using yarn
yarn add --dev zhead
Use this decorator for a simple fully-typed head schema.
import { defineHead } from 'zhead'
const head = defineHead({
title: 'My Page',
})
// {
// title: 'My Page',
// }
Define your meta tags in a simple object with full type-safety.
import { defineHead, resolveMetaFlat } from 'zhead'
const meta = unpackMeta({
contentSecurityPolicy: {
contentSrc: 'none'
},
viewport: {
width: 'device-width',
initialScale: 1,
userScalable: 'yes',
}
})
// [
// { 'http-equiv': 'content-security-policy', content: 'content-src none' },
// { 'name': 'viewport', content: 'width=device-width, user-scalable=yes, initial-scale=1' }
// ]
Turn array meta tags into a flat packed object.
import { defineHead, resolveMetaFlat } from 'zhead'
const meta = packMeta([
{
'content': 'default-src \'self\' https://example.com; content-src none',
'http-equiv': 'content-security-policy',
},
{
name: 'description',
content: 'desc',
},
{
content: '1234567890',
property: 'fb:app_id',
},
])
// {
// "description": "desc",
// "fbAppId": "1234567890",
// "contentSecurityPolicy": "default-src 'self' https://example.com; content-src none"
// }
Generate a minimal SEO head with maximum SEO.
Internally this function uses the withDefaults
and inferSocialShare
utilities.
- Adds utf-8 charset
- Sets default best practice viewport
- Infers social share tags from
title
anddescription
- Sets twitter card to
summary_large_image
- Sets robots best practice
import { resolveSeoHead, resolveMetaFlat } from 'zhead'
const head = resolveSeoHead({
title: 'Learn about zHead - zHead',
description: 'Describing the basic usage of zHead.',
})
// {
// "title": "My Title",
// "meta": [
// {
// "content": "Some description",
// "name": "description",
// },
// {
// "charset": "utf-8",
// },
// {
// "content": "initial-scale=1, width=device-width",
// "name": "viewport",
// },
// {
// "content": "My Title",
// "property": "og:title",
// },
// {
// "content": "Some description",
// "property": "og:description",
// },
// {
// "content": "max-snippet:-1, max-image-preview:large, max-video-preview:-1",
// "name": "robots",
// },
// ],
// }
import { generateHtml } from 'zhead'
const html = generateHtml({
title: 'test',
script: [
{ src: 'https://example.com/script.js' },
],
meta: [
{ name: 'description', content: 'test' },
]
})
// <title>test</title>
// <meta content="test" name="description">
// <script src="https://example.com/script.js"></script>
import { generateTags } from 'zhead'
const tags = generateTags({
title: 'test',
script: [
{ src: 'https://example.com/script.js' },
],
meta: [
{ name: 'description', content: 'test' },
]
})
// [
// {
// "props": {
// "children": "test",
// },
// "tag": "title",
// },
// {
// "props": {
// "content": "test",
// "name": "description",
// },
// "tag": "meta",
// },
// {
// "props": {
// "src": "https://example.com/script.js",
// },
// "tag": "script",
// },
// ]
MIT License Β© 2022-PRESENT Harlan Wilton