npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

norma-design-lint

v1.24.0

Published

Lint HTML/CSS against the Norma web design standard — contrast, focus rings, semantic HTML, labels, reduced-motion, and the common AI-generated design tells.

Downloads

2,887

Readme

English · Tiếng Việt

norma-design-lint

Kiểm HTML/CSS theo chuẩn thiết kế web Norma — tương phản, vòng focus, HTML ngữ nghĩa, nhãn biểu mẫu, reduced-motion, và các "dấu hiệu" thiết kế do AI sinh thường gặp. Thông báo song ngữ (EN/VI) qua --lang, xuất SARIF cho GitHub.

Cách dùng

npx norma-design-lint "**/*.{html,css,jsx,tsx}"
npx norma-design-lint index.html --lang vi
npx norma-design-lint src --format sarif > design-lint.sarif

Mã thoát khác 0 khi có bất kỳ phát hiện mức error, nên nó chặn được CI.

Áp dụng lên codebase có sẵn: chạy --update-baseline một lần để đóng băng các phát hiện hiện tại vào .norma-baseline.json (commit nó), rồi truyền --baseline .norma-baseline.json để CI chỉ fail trên nợ thiết kế mới. GitHub code scanning: --format sarif xuất SARIF 2.1.0 đầy đủ (metadata rule, helpUri, fingerprint độc-lập-với-dòng) — upload bằng github/codeql-action/upload-sarif để có annotation trên PR và danh sách alert ở tab Security. Tóm tắt một lần chạy: --format markdown in bảng theo domain / theo rule (kèm delta baseline) — append vào $GITHUB_STEP_SUMMARY để có ảnh chụp dễ đọc trong Actions UI (xem examples/ci-recipe.yml).

Tùy chọn

| Tùy chọn | Mô tả | |---|---| | --format <stylish\|json\|sarif\|markdown> | Định dạng đầu ra (mặc định stylish). json = báo cáo máy đọc gọn (đường dẫn tương đối repo, message theo một --lang). markdown = bảng tóm tắt theo domain / rule cho GitHub Step Summary hoặc PR comment. | | --lang <en\|vi> | Ngôn ngữ thông báo (mặc định en, hoặc NORMA_LANG). | | --config <path> | File cấu hình (mặc định .normarc.json nếu có). | | --rules <path> | Đường dẫn catalog rule (mặc định: standard/rules.json đóng kèm). | | --tokens <path> | File token DTCG → bật token-binding: cờ một giá trị CSS thô trùng khít token đã định nghĩa (ví dụ oklch(…) hard-code bằng color.brand.azure) và trỏ tới token. Bản này chỉ xét màu; vô hiệu nếu không có cờ này. | | --quiet | Chỉ báo lỗi. | | --max-warnings <n> | Exit khác 0 nếu số cảnh báo vượt n (để CI gate cả rule mức warn, không chỉ error). | | --max-per-rule <n> | Giới hạn số phát hiện mỗi rule LIỆT KÊ trong stylish/json, để một rule nổ hàng nghìn lần không làm ngập context của agent hay log CI. Số liệu đếm + exit code vẫn là tổng thật; json thêm map truncated theo rule cho phần bị ẩn. Danh sách là mẫu theo rule (có thể bỏ sót cả file) — chạy lại không cap để xem đầy đủ. | | --fix | Tự sửa các rule xác định ngay tại chỗ, rồi lint phần còn lại. | | --baseline <path> | Ẩn các phát hiện đã có trong baseline; chỉ fail trên phát hiện MỚI (áp dụng lên code cũ). | | --update-baseline | (Ghi lại) baseline từ các phát hiện hiện tại (đường dẫn từ --baseline, else .norma-baseline.json). | | -h, --help | Hiện hướng dẫn dùng rồi thoát. |

--fix chỉ đụng các sửa không cần phán đoán: thuộc tính CSS vật lý→logic (margin-leftmargin-inline-start, text-align:leftstart, …) trong file .css, và trong HTML là tabindex dương→0 cùng rel="noopener noreferrer" cho link ngoài target="_blank" chưa có rel. Mọi thứ khác (tương phản, vùng chạm, nhãn, lang, alt, link chết) cần con người quyết định nên chỉ báo, không tự viết lại. Sửa HTML là phẫu-thuật-từng-byte — phần còn lại của file không đổi.

Cấu hình (.normarc.json)

{ "lang": "vi", "rules": { "perf.img-dimensions": "error", "a11y.emoji-icon": "off" } }

Tắt một rule nội tuyến

Trang tham chiếu đánh dấu các demo anti-pattern có chủ đích bằng comment:

/* norma-disable a11y.focus-ring-single -- intentional VIOLATION demo */
.demo:focus-visible { outline: 2px solid blue; box-shadow: 0 0 0 4px red; }

Với HTML, thêm data-norma-disable="rule.id" vào phần tử.

Dùng bên trong Stylelint

Đã dùng Stylelint? Áp dụng nhóm kiểm CSS của Norma (tương phản, focus ring, reduced-motion, thuộc tính logic, thang z-index, tell indigo mặc định, …) chỉ bằng một dòng cấu hình — không cần công cụ CI riêng. Nó kiểm mọi cú pháp Stylelint phân tích được: CSS thuần, và SCSS / Less qua customSyntax (chạy trên chính stylesheet đã parse của Stylelint). stylelint là peer dependency tùy chọn; plugin xuất qua một subpath export.

// stylelint.config.js
export default {
  plugins: ["norma-design-lint/stylelint"],
  rules: {
    "norma/design": true,
    // hoặc truyền tùy chọn: [true, { lang: "vi", rules: { "color.contrast.text": "warn" } }]
  },
};

Mỗi phát hiện của Norma thành một cảnh báo Stylelint ở đúng dòng vi phạm, kèm rule id, theo đúng mức severity của rule (rule mức error làm fail build). Các kiểm dựa trên DOM (label, landmark, heading, …) không áp cho stylesheet — chạy chúng trên HTML bằng CLI ở trên.

Dùng bên trong ESLint

Với component JSX/TSX, chạy hai "tell" thiết kế chuyển được của Norma — tell màu indigo mặc định và tell <div onClick> không phải control ngữ nghĩa — bên trong ESLint hiện có của bạn (flat config):

// eslint.config.js
import norma from "norma-design-lint/eslint";

export default [
  {
    files: ["**/*.{jsx,tsx}"],
    plugins: { norma },
    // hoặc ["error", { lang: "vi", rules: { "antipattern.indigo-default": "off" } }]
    rules: { "norma/design": "error" },
  },
];

Khối này gắn vào flat config có sẵn của bạn — parser JSX/TSX của dự án (typescript-eslint, hoặc espree với languageOptions.parserOptions.ecmaFeatures.jsx) lo việc parse; plugin chỉ đọc source text. eslint là peer dependency tùy chọn; plugin xuất qua subpath và không import gì từ ESLint lúc chạy. Phạm vi ở đây cố ý hẹp — component không phải một trang đã render, nên a11y cấu trúc (landmark, label, tương phản, thứ tự heading) không được kiểm. Kiểm HTML đã build bằng CLI, và CSS bằng plugin Stylelint, để có đủ bộ rule.

Kiểm những gì

Các kiểm tra tĩnh chắc chắn, ít dương tính giả, ánh xạ tới catalog rule của Norma (standard/rules.yaml): tương phản (cặp giá trị đặt cùng chỗ và giải được, kể cả var() + OKLCH), một vòng focus duy nhất, sự hiện diện reduced-motion, nhãn biểu mẫu / placeholder-làm-nhãn, điều khiển ngữ nghĩa (<div onclick>), emoji-làm-icon, kích thước ảnh, kích thước vùng chạm, và "dấu hiệu" gradient indigo mặc định. Những rule mà phân tích tĩnh không kiểm chắc chắn được (thang khoảng cách 8px, sàn chữ thân 16px, ngân sách hiệu năng runtime, và bốn mandate WCAG 2.2 do agent kiểm như 2.4.11 Focus Not Obscured) mang check: manual trong catalog — engine bỏ qua chúng và agent thiết kế Norma thực thi thay.

Kiểm được gì và không kiểm được gì

Linter phân tích đầy đủ HTML và CSS (gồm cả khối <style> và thuộc tính style="…" inline) — mọi rule chạy ở đó.

Template component (.jsx/.tsx/.vue/.svelte) hỗ trợ một phần (MVP): source được quét, chính xác theo dòng, cho hai "dấu hiệu" chuyển được mà không cần DOM đầy đủ — dấu hiệu màu indigo mặc định (antipattern.indigo-default: #667eea/#764ba2/indigo-500 trong class/className/:class, object style, hay giá trị Tailwind tùy ý như bg-[#667eea]) và dấu hiệu click trên <div> (a11y.semantic-control: phần tử HTML thường có xử lý click — onClick / @click / v-on:click / on:click — mà không có role ARIA; <Component> được bỏ qua). A11y cấu trúc phụ thuộc cây render — landmark, thứ tự heading, nhãn, tương phản — không kiểm ở đây, vì file component không phải một trang; hãy chạy chúng trên HTML/CSS đã build. Khối <style> trong SFC Vue/Svelte chưa được lint như CSS.

CSS-in-JS và ngữ nghĩa class Tailwind tổng quát nằm ngoài phạm vi ở đây theo thiết kế: ngữ nghĩa cây component sâu thuộc về tầng agent (AGENTS.md, các file rule Cursor/Copilot/Claude) sinh từ cùng catalog — không phải một parser nặng hơn bên trong linter. Hãy lint HTML/CSS đã build bằng CLI để có đủ bộ rule.

Kiểm tra design token

Ngoài HTML/CSS, Norma còn kiểm một file W3C DTCG theo hồ sơ Norma — cấu trúc DTCG (kế thừa $type, phân biệt group/token, hình dạng giá trị theo từng kiểu) cộng tính toàn vẹn tham chiếu alias (một {group.token} không phân giải được, hay một vòng lặp tham chiếu, sẽ bị bắt — JSON Schema thuần không làm được). Màu chấp nhận dạng chuỗi CSS oklch()/hex, quy ước dễ đọc của Norma:

npx norma-design-lint tokens validate tokens.tokens.json

Mã thoát 0 khi hợp lệ, 1 khi có lỗi cấu trúc. $type sai, dimension/duration hỏng, alias treo/vòng lặp là lỗi; một khóa $-prefix lạ là cảnh báo (tương thích với các bản spec tương lai).

Cưỡng chế một DESIGN.md lên mã nguồn của bạn (interop Google Stitch)

DESIGN.md — format mở của Google Stitch — khai báo token của một design system, và CLI của nó validate + export file spec. Thứ nó không làm được là kiểm tra xem HTML/CSS đã ship của bạn có thực sự dùng các token đó không. Norma chính là tầng còn thiếu đó: export DESIGN.md ra W3C DTCG, rồi đưa vào --tokens để token-binding bắt mọi màu thô hard-code một giá trị DESIGN.md đã khai báo thay vì tham chiếu token.

# 1. export token của design system bằng chính CLI của DESIGN.md
npx @google/design.md export --format dtcg DESIGN.md > design.tokens.json
# 2. cưỡng chế lên mã nguồn thật — bước mà validator của DESIGN.md không chạy
npx norma-design-lint "src/**/*.{html,css,jsx,tsx,vue,svelte}" --tokens design.tokens.json

Norma đọc trực tiếp color object có cấu trúc của DTCG ({ colorSpace, components, hex }), nên một color: #1a1c1e trong mã nguồn sẽ bị bắt và trỏ về color.primary. Norma tiêu thụ bản export DTCG, chứ không phải file .md — nó vẫn là một linter đơn nhiệm, không phải một parser DESIGN.md thứ hai.

MCP server (cho AI agent)

Gói kèm một server Model Context Protocol zero-dependency qua stdio, để agent truy vấn chuẩn và lint source ngay trong vòng lặp. Trỏ MCP client tới bin norma-mcp:

{ "mcpServers": { "norma": { "command": "npx", "args": ["-y", "-p", "norma-design-lint", "norma-mcp"] } } }

-p norma-design-lint chọn package và norma-mcp chạy bin MCP-server của nó. Bắt buộc có -p: bin mặc định của package là linter, nên npx norma-design-lint norma-mcp sẽ chạy linter (coi norma-mcp là file glob) chứ không phải server.

Tool: lint_source (lint chuỗi HTML/CSS/JSX → findings), list_rules (catalog, lọc theo domain/tag), get_rule (một rule theo id, kèm rationale + remediation), fix_source (tự sửa các rule xác định trong chuỗi HTML/CSS → nguồn đã sửa + số lần sửa, khép vòng lint→fix→lint-lại), validate_tokens (kiểm chuỗi JSON token DTCG → { valid, tokenCount, errors, warnings }), và get_tokens (bộ design token đã resolve để sinh UI — tên CSS custom-property + giá trị + giá trị concrete sau khi resolve alias, kèm bản đồ theme light/dark, để agent dùng đúng token thay vì giá trị thô; có thể lọc theo group).

API lập trình

import { lintFiles } from "norma-design-lint";
const { findings, errorCount } = lintFiles(["index.html"]);

Giấy phép

MIT.