WithCodeMedia-1-pc
previous arrowprevious arrow
next arrownext arrow

WithCodeMedia-1-sp
previous arrowprevious arrow
next arrownext arrow

Markuplint完全ガイド|全ルール解説・React/Vue/Astro対応・VSCode・pre-commit・GitHub Actions・カスタムルール・段階的導入戦略まで徹底解説

生徒

HTMLのタグの使い方が正しいかどうかを毎回レビューで確認しているんですが、見落としも多くて大変です……自動化できませんか?

ペン博士

Markuplintがその解決策じゃ!HTMLリンターとして、タグの正しい使い方・ARIA属性の適切な設定・アウトライン構造など自動でチェックしてくれるんじゃ。VSCode拡張機能を入れればリアルタイムでエラーを表示してくれるし、pre-commitと組み合わせれば不正なHTMLのコミット自体を防げる。React/Vue/Astro/Svelteにも対応しているんじゃ!

この記事でわかること

  • Markuplintの概要と、ESLintとの違い
  • インストール手順とフレームワーク別(React/Vue/Astro/Svelte)の設定方法
  • 全ルールの解説・エラーレベル設定・ignoreコメントの使い方
  • VSCode拡張・pre-commit(husky+lint-staged)・GitHub Actionsとの連携方法
  • カスタムルール作成・Monorepo対応・既存プロジェクトへの段階的導入戦略

HTMLの品質をレビューに依存していると、レビュワーのスキルによってチェック精度にばらつきが出ます。MarkuplintはHTML専用のリンターで、タグの正しい使い方・ARIAアクセシビリティ・見出しのアウトライン・必須属性など、自動でチェックしてくれます。

本記事では、Markuplintの概要・インストール・全ルール解説・エラーレベルの設定・ignoreコメント・React/Vue/Astro/Svelte対応・VSCode連携・pre-commit+lint-staged連携・GitHub Actionsでの自動化・カスタムルール・monorepo設定・既存PJへの段階的導入戦略・つまずきやすいポイントを完全解説します。


目次

Markuplintとは|HTML専用リンターが解決する問題

Markuplintは、HTMLの構造・セマンティクス・アクセシビリティを自動検証するHTML専用リンターです。JavaScriptを対象とするESLintとは役割が異なり、両者を組み合わせて使うのが理想的です。

>【Markuplintが自動チェックする内容】

✅ HTMLタグの正しい使い方(構造チェック)
→ <p>の中に<div>は入れられない(インライン要素の親にブロック要素)
→ <li>は<ul>/<ol>の直下にのみ置ける
→ <table>の構造チェック(<thead>/<tbody>/<tr>/<td>の正しい配置)
→ 空要素(<img>/<input>)の誤った閉じタグ

✅ アクセシビリティ(ARIA属性)
→ <img>のalt属性が設定されているか
→ aria-label/aria-labelledbyの正しい使い方
→ <button>にアクセシブルな名前があるか
→ インタラクティブ要素の適切なrole

✅ 見出しのアウトライン(heading-levels)
→ h1 → h2 → h3 の正しい順序で使われているか
→ h1 を飛ばして h3 を使っていないか
→ ページにh1が1つだけ存在するか

✅ 必須属性チェック(required-attr)
→ <img>にwidth・heightがあるか(Core Web Vitals対策)
→ <a>にhrefがあるか
→ <input>にid属性があるか

✅ その他のチェック
→ attr-duplication: 重複属性チェック
→ no-boolean-attr-value: boolean属性の値の不要な記述
→ case-sensitive-attr-name: 属性名の大文字小文字チェック
→ character-reference: 文字参照の正しい使い方

【ESLintとの違い】
ESLint: JavaScript/TypeScriptの構文・スタイルをチェック
Markuplint: HTMLの構造・セマンティクス・アクセシビリティに特化
→ 両方を組み合わせて使うのが理想的

インストールと基本設定

># Markuplint本体のインストール
npm install --save-dev markuplint

# 対話式初期設定コマンド(推奨:自動で必要なパッケージを選択・インストール)
npx markuplint --init
# → フレームワークの選択(React/Vue/Svelte/Astro等)
# → 設定ファイルの形式(JSON/YAML/JavaScript)
# → 使用するプリセットルール
# → 必要なパッケージを自動インストール

手動インストール(フレームワーク別)

># React / Next.js (JSX/TSX) 対応
npm install --save-dev markuplint @markuplint/jsx-parser @markuplint/react-spec

# Vue.js (.vue) 対応
npm install --save-dev markuplint @markuplint/vue-parser @markuplint/vue-spec

# Astro (.astro) 対応
npm install --save-dev markuplint @markuplint/astro-parser

# Svelte (.svelte) 対応
npm install --save-dev markuplint @markuplint/svelte-parser

# Pug (.pug) 対応
npm install --save-dev markuplint @markuplint/pug-parser

# WordPress / EJS (.php) 対応
# HTMLパーサーがデフォルトで対応(追加不要)

設定ファイル詳解|.markuplintrc の全オプション

基本的な設定ファイル(HTML専用プロジェクト)

>{
  "$schema": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/markuplint/schemas/markuplintrc.json",

  // プリセットを継承(推奨プリセット)
  "extends": ["markuplint:recommended"],

  "rules": {
    // ===== 構造チェック =====

    // aria-*属性の正しい使い方を検証
    "invalid-attr": true,

    // 要素のコンテンツモデルに違反する子要素を検出
    // 例: <p>の中に<div>が含まれる
    "required-attr": true,

    // 同じ属性名の重複を検出
    "attr-duplication": true,

    // boolean属性に不要な値が記述されている
    // ×: <input disabled="disabled"> → ✅: <input disabled>
    "no-boolean-attr-value": true,

    // ===== アクセシビリティチェック =====

    // ARIAロールの不正な使い方を検出
    "wai-aria": true,

    // label と input の関連付けを検証
    "label-has-control": true,

    // ランドマークのラベル付けを検証
    "landmark-roles": true,

    // 見出しレベルのスキップを検出(h1 → h3 のジャンプ等)
    "heading-levels": {
      "severity": "error",
      "options": {
        "minLevel": 1,
        "allowMultipleH1": false
      }
    },

    // ===== パフォーマンス・品質チェック =====

    // <img>のwidth/height属性(Core Web Vitals対策)
    "required-attr": {
      "options": {
        "attrs": {
          "img": ["src", "alt", "width", "height"]
        }
      }
    },

    // 空の要素を検出(<p></p> など)
    "no-empty-palpable-content": true,

    // 大文字小文字の一貫性
    "case-sensitive-attr-name": true,

    // ===== スタイル設定 =====

    // ファイルのエンコーディング宣言
    "charset": true
  }
}

React / Next.js(JSX/TSX)向け設定

>{
  "$schema": "https://raw.githubusercontent.com/markuplint/markuplint/main/packages/markuplint/schemas/markuplintrc.json",

  // React推奨プリセットを使用
  "extends": ["markuplint:recommended-react"],

  // ファイル種別とパーサーのマッピング
  "parser": {
    "\\.jsx$": "@markuplint/jsx-parser",
    "\\.tsx$": "@markuplint/jsx-parser"
  },

  // ファイル種別とスペックのマッピング
  "specs": {
    "\\.jsx$": "@markuplint/react-spec",
    "\\.tsx$": "@markuplint/react-spec"
  },

  "rules": {
    "invalid-attr": {
      "options": {
        // カスタム属性プレフィックスの無視
        "ignoreAttrNamePrefix": [
          "css",      // CSS Modules: css={{ ... }}
          "data-",    // HTML data属性
          "aria-",    // ARIAはスペックで別途管理
          "x-"        // フレームワーク固有属性
        ]
      }
    },
    "required-attr": true,
    "heading-levels": true,
    "wai-aria": true,

    // JSXでは className を使うため class のチェックを調整
    "no-use-event-handler-attr": false
  },

  // 特定ファイル・ディレクトリを除外
  "excludeFiles": [
    "node_modules/**",
    ".next/**",
    "out/**",
    "coverage/**"
  ]
}

全ルール解説|カテゴリ別一覧

Markuplintのルールは大きく「構造系」「アクセシビリティ系」「コンテンツ品質系」の3カテゴリに分類できます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
【構造系ルール】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

■ invalid-attr
  HTML仕様に存在しない属性・値の型違反を検出
  例: <div hoge="test"> → 'hoge'は無効な属性

■ attr-duplication
  同じ属性を重複して記述した場合に検出
  例: <div class="foo" class="bar"> → 重複エラー

■ no-boolean-attr-value
  boolean属性に不要な値が記述されている場合に検出
  ×: <input disabled="disabled"> → ✅: <input disabled>

■ case-sensitive-attr-name
  属性名の大文字混在を検出
  例: <div Class="foo"> → 'class'が正しい

■ character-reference
  文字参照のエラー(& の代わりに & を直接使用など)

■ no-refer-to-non-existent-id
  aria-labelledbyやfor属性で参照するIDが存在しない場合に検出

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
【アクセシビリティ系ルール】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

■ wai-aria
  ARIAロール・ステート・プロパティの正しい使い方を検証
  例: <div role="button"> ← role=buttonには focusable が必要

■ heading-levels
  見出しレベルのスキップを検出(h1→h3のジャンプ等)
  例: h1の後にh3が来るとエラー

■ label-has-control
  <label>要素がフォームコントロールと正しく関連付けられているか検証
  例: for属性が存在するinputのidと一致しているか

■ landmark-roles
  ランドマーク要素(nav、main、header等)の適切な使用をチェック
  例: <nav> が複数ある場合はaria-labelで区別が必要

■ no-abstract-roles
  抽象的なARIAロール(composite, landmark等)の使用を禁止
  例: <div role="landmark"> → 抽象ロールは直接使用不可

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
【コンテンツ品質系】
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

■ required-attr
  要素に必須とされる属性が欠落している場合に検出
  例: <img>にalt・width・heightがない

■ no-empty-palpable-content
  知覚可能なコンテンツがない要素を検出
  例: <p></p>、<li></li>

■ deprecated-element
  廃止された要素の使用を検出
  例: <center>、<font>、<marquee>

■ no-use-event-handler-attr
  onclickなどのイベントハンドラ属性の直接記述を禁止
  例: <button onclick="fn()"> → JSで addEventListener を使う

エラーレベルの設定|error / warning / false の使い分け

Markuplintではルールごとにエラーレベルを設定できます。既存プロジェクトへの導入時はまずwarningにして、徐々にerrorに昇格させる戦略が効果的です。

設定値動作推奨シーン
true / "error"エラーとして検出・CIをブロック必ず守るべきルール
"warning"警告として表示・CIはブロックしない導入初期・徐々に移行するルール
falseルール無効プロジェクトに合わないルール
>{
  "rules": {
    // エラー: CIをブロックする重大なルール
    "heading-levels": {
      "severity": "error"
    },

    // 警告: 表示はするが通過させる(導入初期)
    "wai-aria": {
      "severity": "warning"
    },

    // 無効: このプロジェクトでは使わないルール
    "no-use-event-handler-attr": false
  }
}

ignoreコメントの使い方

サードパーティコンポーネントや避けられない構造では、ignoreコメントで特定行・特定ルールを無効化できます。

<!-- markuplint-disable heading-levels -->
<h3>サードパーティウィジェット内の見出し</h3>
<!-- markuplint-enable heading-levels -->

<!-- 1行だけ無効にする場合 -->
<!-- markuplint-disable-next-line wai-aria -->
<div role="tooltip" aria-hidden="true">...</div>

<!-- 全ルールを無効にする(非推奨・最小範囲で使う) -->
<!-- markuplint-disable -->
...
<!-- markuplint-enable -->

VSCode拡張機能との連携

>【VSCode Markuplint 拡張機能のインストール】

1. VSCodeを開く
2. 拡張機能(Ctrl+Shift+X)で「Markuplint」を検索
3. 公式の「Markuplint」をインストール
   → 発行者: markuplint

【動作確認】
- .markuplintrc が存在するプロジェクトで HTML/JSX/Vue 等を開く
- エラー箇所が赤波線で表示され、Problems パネルにエラー内容が出る
- ホバーすると該当ルールの説明と修正ヒントが表示される

【settings.json 推奨設定】
{
  "editor.formatOnSave": true,
  "": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "markuplint.enable": true,
  "markuplint.debug.enable": false
}

pre-commit連携|husky + lint-staged の設定

コミット時にMarkuplintを自動実行することで、不正なHTMLがリポジトリに入り込むことを防げます。

># husky と lint-staged のインストール
npm install --save-dev husky lint-staged

# huskyの初期化
npx husky init

# .husky/pre-commit に以下を記述
npx lint-staged
// package.json に lint-staged の設定を追加
{
  "lint-staged": {
    "*.{html,jsx,tsx,vue,astro,svelte}": [
      "markuplint --fix",
      "prettier --write"
    ]
  }
}

GitHub Actionsでの自動化

PRのHTML変更に対してMarkuplintを自動実行し、エラーがあればマージをブロックできます。

# .github/workflows/markuplint.yml
name: Markuplint

on:
  pull_request:
    paths:
      - '**/*.html'
      - '**/*.jsx'
      - '**/*.tsx'
      - '**/*.vue'
      - '**/*.astro'
      - '**/*.svelte'

jobs:
  markuplint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - name: Run Markuplint
        run: npx markuplint "src/**/*.{html,jsx,tsx,vue,astro,svelte}"

Monorepo対応|ルート共通設定と各アプリ固有設定

# Monorepoのディレクトリ構成例
root/
├── .markuplintrc.json  ← 共通設定(全アプリ共通ルール)
├── apps/
│   ├── web/          ← Next.js (TSX)
│   │   └── .markuplintrc.json  ← アプリ固有の設定
│   └── blog/         ← Astro
│       └── .markuplintrc.json  ← アプリ固有の設定
├── packages/
│   └── ui/           ← Reactコンポーネントライブラリ
│       └── .markuplintrc.json
// apps/web/.markuplintrc.json(ルートを継承して上書き)
{
  "extends": ["../../.markuplintrc.json", "markuplint:recommended-react"],
  "parser": {
    "\\.tsx$": "@markuplint/jsx-parser"
  },
  "specs": {
    "\\.tsx$": "@markuplint/react-spec"
  }
}

カスタムルールの作成

プロジェクト固有のHTML規約を強制したい場合、カスタムルールを作成できます。

># カスタムルール例2: 特定のクラス名規約を強制する(BEM命名規則チェック)

// markuplint-rules/bem-class-naming.js
import { createRule } from '@markuplint/ml-core'

// BEM命名規則: block__element--modifier
const bemPattern = /^[a-z][a-z0-9]*(__[a-z][a-z0-9]*)?(--[a-z][a-z0-9]*)?$/

export default createRule({
  name: 'bem-class-naming',
  defaultSeverity: 'warning',
  verify({ attr, report }) {
    if (attr.name !== 'class') return
    const classes = attr.value.split(' ')
    for (const cls of classes) {
      if (cls && !bemPattern.test(cls)) {
        report({
          message: `クラス名 "${cls}" はBEM命名規則に違反しています`,
          line: attr.line,
          col: attr.col,
        })
      }
    }
  },
})
// .markuplintrc.json でカスタムルールを読み込む
{
  "extends": ["markuplint:recommended"],
  "customRules": {
    "bem-class-naming": "./markuplint-rules/bem-class-naming.js"
  },
  "rules": {
    "bem-class-naming": true
  }
}

既存プロジェクトへの段階的導入戦略

大規模な既存プロジェクトへの導入は、一度に全エラーを修正しようとすると破綻します。以下の4ステップで段階的に導入することを推奨します。

  1. Step1: まず動かす――すべてのルールをfalseまたはwarningにしてMarkuplintをインストールし、CIを通す。
  2. Step2: 重要ルールをerrorに昇格――heading-levelsrequired-attrなど影響の大きいルールから順にerrorにする。
  3. Step3: 新規ファイルのみ厳格化――overridesを使い、既存ファイルはwarning・新規ファイルはerrorという設定にする。
  4. Step4: 全ファイルに展開――修正が完了したファイルから順次overrides対象外にしてerrorルールを適用する。
// 段階的導入のための.markuplintrc.json例
{
  "extends": ["markuplint:recommended"],
  "rules": {
    // まずすべてwarningに
    "heading-levels": "warning",
    "wai-aria": "warning",
    "required-attr": "warning"
  },
  "overrides": {
    // 新規ファイル(src/new/配下)はerrorに
    "src/new/**/*.{html,tsx,vue}": {
      "rules": {
        "heading-levels": "error",
        "wai-aria": "error",
        "required-attr": "error"
      }
    }
  }
}

つまずきやすいポイントと対処法

>【よくある問題と解決策】

■ 問題1: アイコンボタンのアクセシブルな名前エラー
<button type="button">
  <svg viewBox="0 0 24 24"><path d="M6 18L18 6M6 6l12 12"/></svg>
</button>
→ エラー: 'button' element has no accessible name

✅ 修正方法1: aria-label を追加
<button type="button" aria-label="閉じる">
  <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
    <path d="M6 18L18 6M6 6l12 12"/>
  </svg>
</button>

✅ 修正方法2: visually-hidden テキストを追加
<button type="button">
  <span class="sr-only">閉じる</span>
  <svg viewBox="0 0 24 24" aria-hidden="true">...</svg>
</button>

■ 問題2: Reactコンポーネントのprops属性エラー
<MyComponent customProp="value" />
→ エラー: 'customProp' is not a valid attribute

✅ 解決: ignoreAttrNamePrefix または ignoreAttrName で除外
"invalid-attr": {
  "options": {
    "ignoreAttrNamePrefix": ["custom"]
  }
}

■ 問題3: 動的なclass名でBEM違反エラー
<div className={`block ${isActive ? 'block--active' : ''}`}>
→ 動的値はMarkuplintが解析できない

✅ 解決: markuplint-disable-next-line で該当行を除外

よくある質問

Q1. Markuplintはどのタイミングで実行すべきですか?

A. VSCode拡張機能でリアルタイムチェック、pre-commitフックでコミット前チェック、GitHub ActionsでPRマージ前チェックの3段階が理想です。重要度の高い順にGitHub Actions(必須)→ pre-commit(推奨)→ VSCode(任意)の順で導入してください。

Q2. 既存プロジェクトへの導入でエラーが大量に出て困っています。どうすればいいですか?

A. 段階的な導入が推奨です。最初はルールを一旦すべて false にするか警告レベルにして Markuplint が動く状態にしてから、段階的にルールを有効にしていく方法が実用的です。特に物量が多い場合はoverridesを使って新規ファイルのみ厳格化し、既存ファイルは後から修正していく方法が現実的です。

Q3. カスタムルールを作りたい場合、どこから始めればいいですか?

A. @markuplint/ml-corecreateRule関数を使います。上述のカスタムルールセクションの実装例を参考にしてください。

Q4. Next.js App Router のサーバーコンポーネント(RSC)での注意点はありますか?

A. Next.js App RouterのサーバーコンポーネントはTypeScript/JSXで記述されるため、通常の@markuplint/jsx-parserで解析可能です。ただし注意点が3つあります。(1)asyncなサーバーコンポーネントの関数宣言はMarkuplintが解析エラーになる可能性があるため、overridesapp/**/*.tsxの一部ルールを調整する必要があります。(2)'use client'ディレクティブはJSXのコメントではないため解析上問題ありません。(3)Metadata APIで生成されるHTMLタグ(titlemeta等)はコンポーネントのJSXに含まれないため、Markuplintのチェック対象外になります。

Q5. チームで一部のメンバーがルールを無視してコミットしてしまいます。強制する方法はありますか?

A. いくつかの方法で強制できます。(1)pre-commitフック(husky + lint-staged): ローカルでコミット時に自動チェック。ただし git commit --no-verify で回避できます。(2)GitHub Actions: PRのCIでMarkuplintを実行し、エラーがあればマージをブロック(Branchプロテクションルールで「Required status checks」に設定)。これは回避不可能で最も確実な方法です。(3)CODEOWNERS + Required Reviews: HTMLファイルの変更に特定レビュワーのapprovalを必須にする。段階的に導入し、最終的にはGitHub ActionsでのCIチェックを必須化するのがベストプラクティスです。


まとめ

  • Markuplint:HTML専用リンター。タグの正しい使い方・ARIA・見出しアウトライン・必須属性を自動チェック。ESLintとの二段構えが推奨。
  • 導入ステップ:npx markuplint –init で対話式初期設定 → VSCode拡張機能 → pre-commit連携 → GitHub Actions の順で段階的に導入。
  • フレームワーク対応:React/Vue/Astro/Svelte/PHPに対応。専用のparserとspecを追加するだけで対応可能。
  • エラーレベル管理:error/warning/falseの3段階。既存PJへの導入時はwarningから始めて段階的にerrorに昇格させる。
  • ignoreコメント:特定行や特定ルールを無効化できる。サードパーティコンポーネントや避けられない構造に使用。
  • Monorepo対応:ルートに共通設定を置き、各アプリがextendsで継承するパターンが管理しやすい。
  • カスタムルール:createRuleでプロジェクト固有のHTML規約を強制できる。BEM命名規則チェックなどを自作可能。
  • GitHub Actions:PRのHTML変更に対して自動でMarkuplintを実行。エラーが行単位のアノテーションとして表示される。

MarkuplintはHTMLの品質をチームで均一に保つための必須ツールです。まずVSCode拡張機能をインストールして、自分のコードがどんなエラーを持っているか確認してみましょう。その後、段階的にpre-commit連携とGitHub Actionsに導入することで、不正なHTMLがリポジトリに入り込むことを根本から防ぐ品質管理の仕組みが完成します。


関連記事


参考リンク(公式・一次情報)


WithCodeを体験できる初級コース公開中!

初級コース(¥49,800)が完全無料に!

  • 期間:1週間
  • 学習内容:
    ロードマップ/基礎知識/環境構築/HTML/CSS/LP・ポートフォリオ作成
    正しい学習方法で「確かな成長」を実感できるカリキュラム。

副業・フリーランスが主流になっている今こそ、自らのスキルで稼げる人材を目指してみませんか?

未経験でも心配することはありません。初級コースを受講される方の大多数はプログラミング未経験です。まずは無料カウンセリングで、悩みや不安をお聞かせください!

この記事を書いた人

WithCode(ウィズコード)は「目指すなら稼げる人材」をビジョンに、累計400名以上のフリーランスを輩出してきた超実践型プログラミングスクールです。150社以上の実案件支援を特徴にWeb制作・Webデザインなどの役立つ情報を現場のノウハウに基づいて発信していきます。

– service –WithGroupの運営サービス

  • WithCode
    - ウィズコード -

    スクール

    「未経験」から
    現場で通用する
    スキルを身に付けよう!

    詳細はこちら
  • WithFree
    - ウィズフリ -

    実案件サポート

    制作会社のサポート下で
    実務経験を積んでいこう!

    詳細はこちら
  • WithCareer
    - ウィズキャリ -

    就転職サポート

    大手エージェントのサポート下で
    キャリアアップを目指そう!

    詳細はこちら

公式サイト より
今すぐ
無料カウンセリング
予約!

目次