├── .editorconfig ├── .eslintrc ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── dependabot-auto-merge.yml ├── .gitignore ├── .husky └── pre-commit ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .stylelintrc ├── gatsby-browser.tsx ├── gatsby-config.ts ├── gatsby-node.ts ├── gatsby-ssr.tsx ├── netlify.toml ├── package-lock.json ├── package.json ├── readme.md ├── src ├── components │ ├── Aside │ │ ├── Aside.tsx │ │ ├── aside.module.css │ │ ├── aside.module.css.d.ts │ │ └── index.ts │ ├── Categories │ │ ├── Categories.tsx │ │ └── index.ts │ ├── Category │ │ ├── Category.tsx │ │ └── index.ts │ ├── Column │ │ ├── Column.tsx │ │ ├── column.module.css │ │ ├── column.module.css.d.ts │ │ └── index.ts │ ├── Content │ │ ├── Content.tsx │ │ ├── content.module.css │ │ ├── content.module.css.d.ts │ │ └── index.ts │ ├── Footer │ │ ├── Footer.tsx │ │ ├── footer.module.css │ │ ├── footer.module.css.d.ts │ │ └── index.ts │ ├── GitHub │ │ ├── GitHub.tsx │ │ ├── github.module.css │ │ ├── github.module.css.d.ts │ │ └── index.ts │ ├── Grid │ │ ├── Grid.tsx │ │ ├── grid.module.css │ │ ├── grid.module.css.d.ts │ │ └── index.ts │ ├── Header │ │ ├── Header.tsx │ │ ├── header.module.css │ │ ├── header.module.css.d.ts │ │ └── index.ts │ ├── Main │ │ ├── Main.tsx │ │ ├── index.ts │ │ ├── main.module.css │ │ └── main.module.css.d.ts │ ├── Navigation │ │ ├── Navigation.tsx │ │ ├── index.ts │ │ ├── navigation.module.css │ │ └── navigation.module.css.d.ts │ ├── Row │ │ ├── Row.tsx │ │ ├── index.ts │ │ ├── row.module.css │ │ └── row.module.css.d.ts │ ├── SEO │ │ ├── SEO.tsx │ │ └── index.ts │ ├── Section │ │ ├── Section.tsx │ │ ├── index.ts │ │ ├── section.module.css │ │ └── section.module.css.d.ts │ └── index.ts ├── constants │ ├── resources.ts │ └── tools.ts ├── data │ ├── anchor │ │ ├── external-links │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ │ └── title-attribute │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ ├── attribute │ │ ├── attribute-case │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ │ ├── attribute-content │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ │ ├── attribute-value │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ │ ├── boolean-attribute │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ │ └── equal-sign │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ ├── comment │ │ ├── comment-marker │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ │ └── single-line-comment │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ ├── css │ │ ├── inline-styles │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ │ └── type │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ ├── document │ │ ├── character-encoding │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ │ └── encoding │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ ├── form │ │ └── input-type │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ ├── general │ │ └── indentation │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ ├── headline │ │ └── heading-hierarchy │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ ├── image │ │ ├── alt-attribute │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ │ └── dimensions │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ ├── javascript │ │ ├── event-handlers │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ │ ├── external-files │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ │ └── type │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ ├── link │ │ └── protocol │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ ├── selector │ │ └── id-class │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ ├── string │ │ └── quotation-marks │ │ │ ├── bad.md │ │ │ ├── good.md │ │ │ └── index.md │ └── tag │ │ ├── closing-tag │ │ ├── bad.md │ │ ├── good.md │ │ └── index.md │ │ ├── empty │ │ ├── bad.md │ │ ├── good.md │ │ └── index.md │ │ ├── newline │ │ ├── bad.md │ │ ├── good.md │ │ └── index.md │ │ ├── self-closing │ │ ├── bad.md │ │ ├── good.md │ │ └── index.md │ │ └── tag-case │ │ ├── bad.md │ │ ├── good.md │ │ └── index.md ├── hooks │ ├── index.tsx │ └── site-metadata.tsx ├── images │ └── favicon.png ├── layouts │ ├── Default │ │ ├── Default.tsx │ │ └── index.ts │ └── index.ts ├── pages │ └── index.tsx └── styles │ └── main.css ├── static ├── googleb71e0a1ab44fbe42.html ├── images │ └── html5.svg └── robots.txt └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_size = 2 9 | indent_style = space 10 | insert_final_newline = true 11 | trim_trailing_whitespace = true 12 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true, 5 | "jest": true, 6 | "node": true 7 | }, 8 | "extends": [ 9 | "airbnb", 10 | "plugin:@typescript-eslint/recommended", 11 | "plugin:import/typescript", 12 | "plugin:react/recommended", 13 | "prettier" 14 | ], 15 | "overrides": [ 16 | { 17 | "files": ["**/*.tsx"], 18 | "rules": { 19 | "react/prop-types": "off" 20 | } 21 | } 22 | ], 23 | "parserOptions": { 24 | "ecmaFeatures": { 25 | "jsx": true 26 | }, 27 | "ecmaVersion": 12, 28 | "sourceType": "module" 29 | }, 30 | "plugins": ["react"], 31 | "rules": { 32 | "@typescript-eslint/no-use-before-define": 0, 33 | "import/extensions": [ 34 | "error", 35 | "ignorePackages", 36 | { 37 | "js": "never", 38 | "jsx": "never", 39 | "ts": "never", 40 | "tsx": "never" 41 | } 42 | ], 43 | "import/no-unresolved": 0, 44 | "no-use-before-define": 0, 45 | "react/jsx-filename-extension": [ 46 | 1, 47 | { 48 | "extensions": [".js", ".jsx", ".ts", ".tsx"] 49 | } 50 | ], 51 | "react/jsx-props-no-spreading": 0 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'npm' 4 | directory: '/' 5 | schedule: 6 | interval: 'monthly' 7 | groups: 8 | minor-and-patch: 9 | update-types: 10 | - 'patch' 11 | - 'minor' 12 | eslint: 13 | patterns: 14 | - '@typescript-eslint/*' 15 | - 'eslint*' 16 | gatsby: 17 | patterns: 18 | - 'gatsby*' 19 | lodash: 20 | patterns: 21 | - '@types/lodash-es' 22 | - 'lodash-es' 23 | react: 24 | patterns: 25 | - '@types/react-dom' 26 | - '@types/react' 27 | - 'react-dom' 28 | - 'react' 29 | stylelint: 30 | patterns: 31 | - 'stylelint*' 32 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: marcobiedermann/actions/.github/actions/checkout@main 15 | - uses: marcobiedermann/actions/.github/actions/setup-node@main 16 | 17 | - name: 🔋 Install 18 | run: npm ci 19 | 20 | - name: 🤖 Linting 21 | run: npm run lint 22 | 23 | - name: 🛠️ Building 24 | run: npm run build 25 | -------------------------------------------------------------------------------- /.github/workflows/dependabot-auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto-merge 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | ci: 7 | uses: marcobiedermann/actions/.github/workflows/dependabot-auto-merge.yml@main 8 | secrets: inherit 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | public 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v20 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | public 4 | src/data 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "singleQuote": true, 4 | "trailingComma": "all" 5 | } 6 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-standard"], 3 | "plugins": ["stylelint-selector-bem-pattern", "stylelint-order"], 4 | "rules": { 5 | "selector-class-pattern": null, 6 | "order/properties-alphabetical-order": true, 7 | "plugin/selector-bem-pattern": { 8 | "componentName": "[A-Z]+", 9 | "componentSelectors": { 10 | "initial": "^\\.{componentName}(?:-[a-z]+)?$", 11 | "combined": "^\\.combined-{componentName}-[a-z]+$" 12 | }, 13 | "utilitySelectors": "^\\.util-[a-z]+$" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /gatsby-browser.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/prefer-default-export */ 2 | 3 | import { WrapPageElementBrowserArgs } from 'gatsby'; 4 | import 'prismjs/themes/prism.css'; 5 | import React from 'react'; 6 | import { Default } from './src/layouts'; 7 | import './src/styles/main.css'; 8 | 9 | function wrapPageElement({ element, props }: WrapPageElementBrowserArgs): JSX.Element { 10 | return {element}; 11 | } 12 | 13 | export { wrapPageElement }; 14 | -------------------------------------------------------------------------------- /gatsby-config.ts: -------------------------------------------------------------------------------- 1 | import type { GatsbyConfig } from 'gatsby'; 2 | import { resolve } from 'node:path'; 3 | 4 | const config: GatsbyConfig = { 5 | siteMetadata: { 6 | title: 'HTML Style Guide', 7 | description: 'A style guide which helps you write better, performant, structured, scalable and maintainable HTML.', 8 | author: '@BiedermannMarco', 9 | github: { 10 | url: 'https://github.com/marcobiedermann/html-style-guide', 11 | }, 12 | }, 13 | plugins: [ 14 | { 15 | resolve: 'gatsby-plugin-manifest', 16 | options: { 17 | name: 'HTML Style Guide', 18 | short_name: 'HTMLStyleGuide', 19 | start_url: '/', 20 | background_color: '#e34f26', 21 | theme_color: '#e34f26', 22 | display: 'minimal-ui', 23 | icon: 'src/images/favicon.png', 24 | }, 25 | }, 26 | { 27 | resolve: 'gatsby-source-filesystem', 28 | options: { 29 | name: 'data', 30 | path: resolve('src/data'), 31 | }, 32 | }, 33 | { 34 | resolve: 'gatsby-transformer-remark', 35 | options: { 36 | plugins: [ 37 | { 38 | resolve: 'gatsby-remark-autolink-headers', 39 | }, 40 | { 41 | resolve: 'gatsby-remark-prismjs', 42 | }, 43 | ], 44 | }, 45 | }, 46 | ], 47 | }; 48 | 49 | export default config; 50 | -------------------------------------------------------------------------------- /gatsby-node.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Node APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/node-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /gatsby-ssr.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/prefer-default-export */ 2 | 3 | import { WrapPageElementBrowserArgs } from 'gatsby'; 4 | import React from 'react'; 5 | import { Default } from './src/layouts'; 6 | 7 | function wrapPageElement({ element, props }: WrapPageElementBrowserArgs): JSX.Element { 8 | return {element}; 9 | } 10 | 11 | export { wrapPageElement }; 12 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "npm run build" 3 | publish = "public/" 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "html-style-guide", 3 | "version": "1.0.0", 4 | "description": "A style guide which helps you write better, performant, structured, scalable and maintainable HTML.", 5 | "private": "true", 6 | "scripts": { 7 | "build": "gatsby build", 8 | "check": "tsc --noEmit", 9 | "clean": "gatsby clean", 10 | "develop": "gatsby develop", 11 | "fix:css": "npm run lint:css -- --fix", 12 | "fix:js": "npm run lint:js -- --fix", 13 | "fix": "npm run fix:css && npm run fix:js", 14 | "format": "prettier --write .", 15 | "lint:css": "stylelint --ignore-path .gitignore '**/*.css'", 16 | "lint:js": "eslint --ignore-path .gitignore '**/*.{js,jsx,ts,tsx}'", 17 | "lint": "npm run lint:css && npm run lint:js", 18 | "prepare": "husky", 19 | "pretty-quick": "pretty-quick --staged", 20 | "serve": "gatsby serve", 21 | "update": "npx npm-check-updates --format group --interactive" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/marcobiedermann/html-style-guide.git" 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/marcobiedermann/html-style-guide/issues" 29 | }, 30 | "keywords": [ 31 | "html", 32 | "style", 33 | "coding", 34 | "guide", 35 | "styleguide", 36 | "best practices", 37 | "tips" 38 | ], 39 | "author": "Marco Biedermann", 40 | "homepage": "https://www.marcobiedermann", 41 | "license": "ISC", 42 | "dependencies": { 43 | "gatsby": "^5.14.3", 44 | "gatsby-plugin-manifest": "^5.14.0", 45 | "gatsby-remark-autolink-headers": "^6.14.0", 46 | "gatsby-remark-prismjs": "^7.14.0", 47 | "gatsby-source-filesystem": "^5.14.0", 48 | "gatsby-transformer-remark": "^6.14.0", 49 | "lodash-es": "^4.17.21", 50 | "prismjs": "^1.30.0", 51 | "react": "^18.3.1", 52 | "react-dom": "^18.3.1" 53 | }, 54 | "devDependencies": { 55 | "@types/lodash-es": "^4.17.12", 56 | "@typescript-eslint/eslint-plugin": "^7.11.0", 57 | "@typescript-eslint/parser": "^7.11.0", 58 | "eslint": "^8.51.0", 59 | "eslint-config-airbnb": "^19.0.4", 60 | "eslint-config-prettier": "^9.1.0", 61 | "eslint-plugin-import": "^2.31.0", 62 | "eslint-plugin-jsx-a11y": "^6.10.1", 63 | "eslint-plugin-react": "^7.37.2", 64 | "eslint-plugin-react-hooks": "^4.6.2", 65 | "husky": "^9.1.7", 66 | "lint-staged": "^15.5.1", 67 | "prettier": "^3.5.3", 68 | "stylelint": "^16.14.1", 69 | "stylelint-config-standard": "^36.0.1", 70 | "stylelint-order": "^6.0.4", 71 | "stylelint-selector-bem-pattern": "^4.0.1", 72 | "typescript": "^5.8.3" 73 | }, 74 | "lint-staged": { 75 | "**/*": "npm run format" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # HTML Style Guide 2 | 3 | ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/marcobiedermann/html-style-guide/ci.yml) 4 | ![Netlify](https://img.shields.io/netlify/013a52b4-4533-4fdb-848c-8fc7dd0f584b) 5 | 6 | A style guide which helps you write better, performant, structured, scalable and maintainable HTML. 7 | -------------------------------------------------------------------------------- /src/components/Aside/Aside.tsx: -------------------------------------------------------------------------------- 1 | import React, { HTMLAttributes, ReactNode } from 'react'; 2 | import { aside } from './aside.module.css'; 3 | 4 | interface AsideProps extends HTMLAttributes { 5 | children: ReactNode; 6 | } 7 | 8 | function Aside(props: AsideProps): JSX.Element { 9 | return