テンプレートの安全性と HTML の構造
このルール群では、HTML の挿入や URL の指定、属性と ID の重複、textarea・コンポーネントへのテキストの渡し方、HTML の入れ子を確認します。
外部から受け取った値を表示するときや、リンク・フォームを追加するとき、同じコンポーネントを複数表示するときに確認してください。
たとえば、HTML を挿入せずテキストとして表示する例とフォームの ID を生成して関連付ける例では、悪い例と良い例の差を確認できます。採用するルールだけを掲載された設定で有効にし、vp run lint を実行してください。Vue の全ルールから関連するテンプレートの検査も確認できます。
このページに、各ルールの目的・前提・設定と、省略のない悪い例・良い例をまとめています。変更箇所は行の色で示します。コードをコピーすると、ソースコード全体を取得できます。各例に現在の対応範囲も明記しています。
| ルール | 例 | 目的 |
|---|---|---|
vue/no-duplicate-attributes |
悪い · 良い | 同じ要素の属性重複を検出します。 |
vue/no-textarea-mustache |
悪い · 良い | textarea 内の mustache を検出し、v-model の使用を勧めます。 |
vue/no-unsafe-url |
悪い · 良い | 危険なスキームを含む可能性がある URL 属性やバインディングを検出します。 |
vue/no-v-html |
悪い · 良い | XSS を防ぐため、v-html を使用した箇所に警告を出します。 |
vue/no-v-text-v-html-on-component |
悪い · 良い | コンポーネントでの v-text / v-html を検出します。 |
vue/permitted-contents |
悪い · 良い | HTML の要素ごとのコンテンツモデルを検査します。 |
vue/use-unique-element-ids |
悪い · 良い | 静的 ID の代わりに useId() で一意な ID を生成します。 |
全ルール · ルールのオプション · ESLint 移行対応表 · プロジェクトの検査 · 子への属性の継承
vue/no-duplicate-attributes
同じ要素の属性重複を検出します。
既定の重大度: error
プリセット: essential, happy-path, nuxt, ecosystem, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC のテンプレートと各ブロック。ルールに必要な script の文脈も例に含めています。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。
設定(Vite+)
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({
vue: {
linter: {
"preset": "incremental",
"rules": {
"vue/no-duplicate-attributes": "error"
}
},
},
});
vp run lint
悪い
一つの button に class を二回指定しています。
<template>
<button class="primary" class="large">Save</button>
</template>
良い
二つのクラスを一つの class 属性にまとめます。
<template>
<button class="primary large">Save</button>
</template>
良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。
vue/no-textarea-mustache
textarea 内の mustache を検出し、v-model の使用を勧めます。
既定の重大度: error
プリセット: essential, happy-path, nuxt, ecosystem, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC のテンプレートと各ブロック。ルールに必要な script の文脈も例に含めています。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。
設定(Vite+)
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({
vue: {
linter: {
"preset": "incremental",
"rules": {
"vue/no-textarea-mustache": "error"
}
},
},
});
vp run lint
悪い
textarea の値をバインドせず、要素内のテキスト補間に message を記述しています。
<template>
<textarea>{{ message }}</textarea>
</template>
良い
v-model で、編集可能な textarea の値と message を関連付けます。
<template>
<textarea v-model="message"></textarea>
</template>
良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。
vue/no-unsafe-url
危険なスキームを含む可能性がある URL 属性やバインディングを検出します。
既定の重大度: warning
プリセット: essential, happy-path, nuxt, ecosystem, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC のテンプレートと各ブロック。ルールに必要な script の文脈も例に含めています。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。
設定(Vite+)
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({
vue: {
linter: {
"preset": "incremental",
"rules": {
"vue/no-unsafe-url": "warn"
}
},
},
});
vp run lint
悪い
a の移動先に、JavaScript を実行する javascript: スキームを使っています。
<template>
<a href="javascript:alert(1)">Continue</a>
</template>
良い
移動先を、通常のローカルパス /next に変更します。
<template>
<a href="/next">Continue</a>
</template>
良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。
vue/no-v-html
XSS を防ぐため、v-html を使用した箇所に警告を出します。
既定の重大度: warning
プリセット: essential, happy-path, nuxt, ecosystem, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC のテンプレートと各ブロック。ルールに必要な script の文脈も例に含めています。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。
設定(Vite+)
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({
vue: {
linter: {
"preset": "incremental",
"rules": {
"vue/no-v-html": "warn"
}
},
},
});
vp run lint
悪い
v-html で content を通常の文字ではなく HTML として扱っています。
<template>
<article v-html="content" />
</template>
良い
mustache の補間で、HTML を挿入せず content をエスケープしたテキストとして表示します。
<template>
<article>{{ content }}</article>
</template>
良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。
vue/no-v-text-v-html-on-component
コンポーネントでの v-text / v-html を検出します。
既定の重大度: error
プリセット: essential, happy-path, nuxt, ecosystem, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC のテンプレートと各ブロック。ルールに必要な script の文脈も例に含めています。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。
設定(Vite+)
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({
vue: {
linter: {
"preset": "incremental",
"rules": {
"vue/no-v-text-v-html-on-component": "error"
}
},
},
});
vp run lint
悪い
コンポーネントに、要素の内容を置き換える v-html や v-text を指定しています。
<template>
<MyComponent v-html="content" />
<MyComponent v-text="content" />
</template>
良い
標準の HTML 要素にはディレクティブを使えます。MyComponent にはデフォルトスロットから内容を渡します。
<template>
<div v-html="content"></div>
<component is="div" v-html="content" />
<MyComponent>{{ content }}</MyComponent>
</template>
良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。
vue/permitted-contents
HTML の要素ごとのコンテンツモデルを検査します。
既定の重大度: error
プリセット: happy-path, nuxt, ecosystem, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC のテンプレートと各ブロック。ルールに必要な script の文脈も例に含めています。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。
設定(Vite+)
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({
vue: {
linter: {
"preset": "incremental",
"rules": {
"vue/permitted-contents": "error"
}
},
},
});
vp run lint
悪い
p にブロック要素を入れたり、tbody を省略したりしています。操作要素の入れ子や、ul の直下に div を置く例もあります。
<template>
<p><div>block in a paragraph</div></p>
<table><tr><td>row without tbody</td></tr></table>
<a href="#"><button type="button">nested control</button></a>
<ul><div>not a list item</div></ul>
</template>
良い
p はインラインの内容、table は tbody、ul は li を使います。独自コンポーネントの MyItem は、ul の子となる既知の HTML 要素としては検査されません。
<template>
<p><span>inline in a paragraph</span></p>
<table><tbody><tr><td>cell</td></tr></tbody></table>
<ul><li>list item</li><MyItem /></ul>
</template>
良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。
vue/use-unique-element-ids
静的 ID の代わりに useId() で一意な ID を生成します。
既定の重大度: warning
プリセット: nuxt, opinionated
自動修正: なし。修正内容を確認してください
適用範囲: Vue SFC のテンプレートと各ブロック。ルールに必要な script の文脈も例に含めています。
オプション: ルール固有のオプションはありません。重大度とプリセットは設定できます。
設定(Vite+)
import { defineConfig } from "@vizejs/vite-plugin/vite-plus";
export default defineConfig({
vue: {
linter: {
"preset": "incremental",
"rules": {
"vue/use-unique-element-ids": "warn"
}
},
},
});
vp run lint
悪い
固定の email ID がコンポーネントの各インスタンスで重複し、複数表示時に label の参照先が曖昧になります。
<template>
<label for="email">Email</label>
<input id="email" />
</template>
良い
useId() の emailId を label の for と input の id の両方にバインドします。
<script setup>
import { useId } from "vue";
const emailId = useId();
</script>
<template>
<label :for="emailId">Email</label>
<input :id="emailId" />
</template>
良い例は上記の設定でこのルールの診断が出ない例です。他のルールの診断は出る場合があります。