Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: keep template variable in HTML attribute name on one line (#1185) - #2206

Merged
monosans merged 2 commits into
djlint:masterfrom
apoorvdarshan:fix/issue-1185-template-var-in-attribute-name
Jul 11, 2026
Merged

fix: keep template variable in HTML attribute name on one line (#1185)#2206
monosans merged 2 commits into
djlint:masterfrom
apoorvdarshan:fix/issue-1185-template-var-in-attribute-name

Conversation

@apoorvdarshan

Copy link
Copy Markdown
Contributor

Fixes #1185

Root cause

The attribute tokenizer (Config.attribute_pattern in src/djlint/settings.py) matched an attribute name with the subpattern (?:\w|-|\.|\:|@|/(?!>))+, which only accepts plain name characters. When a template variable is embedded in an attribute name — e.g. data-{{ st_controller }}-target — the run stops at the {{, so data- is matched as one attribute name, the {{ st_controller }} is then picked up by the standalone-template-tag branch, and -target="documentFile" is matched as a third, separate attribute.

During attribute expansion (src/djlint/formatter/attributes.py), each token is emitted on its own line, so the single attribute is corrupted into three lines.

Reproduction

Input:

<input type="file" name="file" class="d-none" data-{{ st_controller }}-target= "documentFile" multiple />

Actual (wrong) output on 1.36.4 and current master:

<input type="file"
       name="file"
       class="d-none"
       data-
       {{ st_controller }}
       -target="documentFile"
       multiple />

Corrected output with this change:

<input type="file"
       name="file"
       class="d-none"
       data-{{ st_controller }}-target="documentFile"
       multiple />

Fix

Extend the attribute-name subpattern so a template tag ({{ ... }} or {% ... %}) may appear inside a name. The name must still start with a real name character, and the embedded tag uses an atomic group (?>...) to avoid pathological backtracking:

(?:\w|-|\.|\:|@|/(?!>))                       # a name character
(?:
    (?:\w|-|\.|\:|@|/(?!>))                    # more name characters
  | (?>{{ ... }}|{% ... %})                    # or an embedded template tag
)*
| required | checked

The change is localized to the name portion of the pattern only. Because a name must begin with a name character, a standalone template tag ({{ x }}, {% if %}...{% endif %}) still falls through to the existing standalone branch, so that behaviour is unchanged. Values, quoting, and boolean attributes are untouched.

Tests

Added a regression case template_var_in_attribute_name to tests/test_html/test_attributes.py. It fails on master (producing the three-line output shown above) and passes with this fix.

The full test suite passes locally (678 passed; the one unrelated failure, test_python_call, fails identically on unmodified master in this environment because it invokes a bare python binary that is not on PATH here). ruff check and ruff format --check are clean on the changed files. I also smoke-tested standalone template tags, {% if %}-wrapped booleans, template vars in values, and multiple template vars within one name to confirm no regressions.

Disclosure: prepared with AI assistance; reviewed and verified locally.

…t#1185)

The attribute tokenizer split an attribute name that embeds a template
variable, e.g. `data-{{ st_controller }}-target="..."`, into three
separate tokens (`data-`, `{{ st_controller }}`, `-target="..."`).
Because each token is emitted on its own line during attribute
expansion, the resulting output was corrupted.

The attribute-name subpattern only matched plain name characters, so a
`{{ ... }}` (or `{% ... %}`) in the middle of a name terminated the run
and the remainder was picked up by the standalone-template-tag branch.

Allow an embedded template tag inside an attribute name (anchored by a
leading name character, using an atomic group to avoid backtracking) so
`data-{{ x }}-target` is recognised as a single attribute name. Pure
standalone template tags (`{{ x }}`, `{% if %}...{% endif %}`) still
fall through to the standalone branch, preserving existing behaviour.
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ae4abf04-4752-4d72-9d02-61e6bff31178

📥 Commits

Reviewing files that changed from the base of the PR and between 02cc6b1 and 624b44e.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/djlint/settings.py
  • tests/test_html/test_attributes.py

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved formatting for HTML attribute names that include template expressions, preserving valid template syntax when wrapping attributes.
    • Enhanced consistency of spacing and line wrapping for self-closing elements.
  • Tests
    • Added formatter test coverage for attribute names containing embedded template tags and template-based prefixes/suffixes.
  • Documentation
    • Updated the changelog with an Unreleased entry for the template-preservation fix.

Walkthrough

The attribute-pattern regex now recognizes template expressions within HTML attribute names. Three parametrized tests cover embedded, leading, and complete template-based names, and the changelog documents the fix.

Changes

Templated Attribute Name Formatting Fix

Layer / File(s) Summary
Regex fix and formatting validation
src/djlint/settings.py, tests/test_html/test_attributes.py, CHANGELOG.md
Updated attribute_pattern to match name characters and embedded {{...}}/{%...%} template tags while retaining required and checked alternatives. Added tests for embedded, leading, and complete templated attribute names, and documented the fix.

Possibly related PRs

  • djlint/djLint#2084: Also modifies the attribute_pattern regex to handle template constructs inside attributes.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately describes the main fix for template variables in HTML attribute names.
Description check ✅ Passed The description is detailed and covers the issue, root cause, reproduction, fix, and tests, though it doesn't follow the template exactly.
Linked Issues check ✅ Passed The code change and regression test directly address #1185 by preserving embedded template variables inside attribute names.
Out of Scope Changes check ✅ Passed The changes stay focused on the formatter fix, its regression test, and a changelog note with no obvious unrelated scope.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@monosans
monosans enabled auto-merge (squash) July 11, 2026 18:52
@monosans
monosans merged commit 1085e94 into djlint:master Jul 11, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] [Formatter] Template Variable in HTML Attribute gets formatted to multi-lines

2 participants