Linter Usage

djLint includes many rules to check the style and validity of your templates. Take full advantage of the linter by configuring it to use a preset profile for the template language of your choice.

djlint /path/to/templates --lint

# with custom extensions
djlint /path/to/templates -e html.dj --profile=django

# or to file
djlint /path/to/this.html.j2  --profile=jinja

Enabling or Disabling Rules

Most rules are enabled by default. Rules can be disabled in the command line with the --ignore flag. Rules can be enabled with the --include flag.

For example:

djlint . --lint --include=H017,H035 --ignore=H013,H015

This can also be done through the Configuration file.

Rules

Code Meaning Default
D004 (Django) Static urls should follow {% static path/to/file %} pattern. ✔️
D018 (Django) Internal links should use the {% url ... %} pattern. ✔️
H005 Html tag should have lang attribute. ✔️
H006 img tag should have height and width attributes. ✔️
H007 <!DOCTYPE ... > should be present before the html tag. ✔️
H008 Attributes should be double quoted. ✔️
H009 Tag names should be lowercase. ✔️
H010 Attribute names should be lowercase. ✔️
H011 Attribute values should be quoted. ✔️
H012 There should be no spaces around attribute =. ✔️
H013 img tag should have alt attributes. ✔️
H014 More than 2 blank lines. ✔️
H015 Follow h tags with a line break. ✔️
H016 Missing title tag in html. ✔️
H017 Void tags should be self closing. -
H019 Replace javascript:abc() with on_ event and real url. ✔️
H020 Empty tag pair found. Consider removing. ✔️
H021 Inline styles should be avoided. ✔️
H022 Use HTTPS for external links. ✔️
H023 Do not use entity references. ✔️
H024 Omit type on scripts and styles. ✔️
H025 Tag seems to be an orphan. ✔️
H026 Empty id and class tags can be removed. ✔️
H029 Consider using lowercase form method values. ✔️
H030 Consider adding a meta description. ✔️
H031 Consider adding meta keywords. ✔️
H033 Extra whitespace found in form action. ✔️
J004 (Jinja) Static urls should follow {{ url_for('static'..) }} pattern. ✔️
J018 (Jinja) Internal links should use the {% url ... %} pattern. ✔️
T001 Variables should be wrapped in whitespace. Ex: {{ this }} ✔️
T002 Double quotes should be used in tags. Ex {% extends "this.html" %} ✔️
T003 Endblock should have name. Ex: {% endblock body %}. ✔️
T027 Unclosed string found in template syntax. ✔️
T028 Consider using spaceless tags inside attribute values. {%- if/for -%} ✔️
T032 Extra whitespace found in template tags. ✔️
T034 Did you intend to use {% … %} instead of {% … }%? ✔️
H035 Meta tags should be self closing. -
H036 Avoid use of
tags.
-
H037 Duplicate attribute found. ✔️

Code Patterns

The first letter of a code follows the pattern:

  • D: applies specifically to Django
  • H: applies to html
  • J: applies specifically to Jinja
  • M: applies specifically to Handlebars
  • N: applies specifically to Nunjucks
  • T: applies generally to templates

Adding Rules

We welcome pull requests with new rules!

A good rule consists of

  • Name
  • Code
  • Message - Message to display when error is found.
  • Flags - Regex flags. Defaults to re.DOTALL. ex: re.I|re.M
  • Patterns - regex expressions that will find the error.
  • Exclude - Optional list of profiles to exclude rule from.

Please include a test to validate the rule.

Custom Rules

You can add custom rules just for your project by creating a .djlint_rules.yaml alongside
your pyproject.toml. Rules can be added to this files and djLint will pick them up.

Pattern Rules

You can add rules that fails if one of the regex pattern has a match:

- rule:
    name: T001
    message: Find Trichotillomania
    flags: re.DOTALL|re.I
    patterns:
      - Trichotillomania

Python module Rules

You can add rules that import and execute a custom python function:

- rule:
    name: T001
    message: Found the 'bad' word
    python_module: your_package.your_module

The specified python_module must contain a run() function that will be executed on
every checked file. It must accept the following arguments:

  • rule: The dict that represent your rule in .djlint_rules.yaml. You will typically
    use this variable to access the rule name and message.
  • config: The DJLint configuration object.
  • html: The full html content of the file.
  • filepath: Path to the file that we are currently checking.
  • line_ends: List of line start and end character position that you can use with
    djlint.lint.get_line() to get line numbers from a character position. See the example.
  • *args, **kwargs: We might add other arguments in the future, so you should include
    those two arguments to reduce the risk of failure on djLint upgrade.

It must return a list of dict, one for each errors, with the following keys:

  • code: Code name of the rule that report the error (typically rule['name'])
  • line: Line number and character number on this line, separated by a ‘:’ as a string.
    For example "2:3" means that the error has been found on line 2, character 3
  • match: The part of the content that contains the error
  • message: The message that will be printed to signal the error (typically rule['message'])
from typing import Any, Dict, List
from djlint.settings import Config
from djlint.lint import get_line
import re

def run(
    rule: Dict[str, Any],
    config: djlint.settings.Config,
    html: str,
    filepath: str,
    line_ends: List[Dict[str, int]],
    *args: Any,
    **kwargs: Any,
) -> List[Dict[str, str]]:
    """
    Rule that fails if if the html file contains 'bad'. This is just an example, in
    reality it's much simpler to do that with "pattern rule".
    """
    errors: List[Dict[str, str]] = []
    for match in re.finditer(r"bad", html):
        errors.append(
            {
                "code": rule["name"],
                "line": get_line(match.start(), line_ends),
                "match": match.group().strip()[:20],
                "message": rule["message"],
            }
        )
    return errors
Edit this page Updated Jul 12, 2024