ESLint Plugin
@unhead/eslint-plugin checks Unhead calls in source files. It covers a subset of the runtime ValidatePlugin rules, including deprecated v2 properties, missing required attributes, and meta-tag typos.
What Source Lint Catches
Use source lint for issues that can be determined without rendering a head:
- Autofixes rename deprecated properties, add required values, and remove redundant values.
- The plugin reports findings in editors and CI without starting the application.
- Lint, runtime validation, and the CLI share rule IDs from
unhead/validate.
Install
pnpm add -D @unhead/eslint-plugin
Usage
Add the recommended config to your flat ESLint config:
import { configs } from '@unhead/eslint-plugin'
export default [
configs.recommended,
]
For projects migrating from Unhead v2, swap in configs.migration to also wrap tag literals in their defineLink / defineScript helpers for type narrowing.
import { configs } from '@unhead/eslint-plugin'
export default [
configs.migration,
]
Rules
The plugin ships 15 rules. The full table with severity, autofix status, and what each rule catches lives in the package README:
→ @unhead/eslint-plugin rules table
Migration rules include:
no-deprecated-props(error, autofix): rewrites v2 property names that v3 no longer converts.no-unknown-meta(warn, autofix): suggests corrections for typos such asog:descriptin→og:description.invalid-input-shape(warn): catches wrong container shapes and head fields such asmetaortitleTemplatenested insidehtmlAttrsorbodyAttrs.numeric-tag-priority(warn, suggestions): flags numerictagPriorityvalues and suggests'critical' | 'high' | 'low'.prefer-define-helpers(off inrecommended, on inmigration, autofix): wrapslinkandscriptliterals indefineLinkanddefineScriptso Unhead's discriminated unions narrow correctly.
What it can and can't see
Lint rules walk source-level calls into useHead, useHeadSafe, useServerHead, useServerHeadSafe, useSeoMeta, useServerSeoMeta, and the tag helpers defineLink / defineScript. Tag arrays inside meta / link / script / noscript / style and object literals inside htmlAttrs / bodyAttrs are descended automatically.
It cannot see anything that depends on the resolved tag set: cross-tag conflicts (canonical vs og:url), counts (too many preloads), or rendered byte budgets (meta beyond 1MB). Those checks live in the runtime ValidatePlugin and are surfaced by the CLI's validate-html and validate-url commands.
Calls, identifiers, refs, and computed expressions have an unknown static shape, so this rule leaves them for runtime validation.
Editor integration
Editors that run ESLint through the VS Code or JetBrains integration expose fixes for autofixable rules. The numeric-tag-priority rule also offers a suggestion for each priority alias.