djLint
djLint copied to clipboard
[FEATURE] Multi-line classes
Using tailwind in django templates, so there's a lot of classes. It's easier to keep them broken into several lines for easier readability.
<a
href="foo"
class="
inline-flex items-center p-4
bg-white hover:bg-gray-200
text-sm font-medium text-gray-500 hover:text-gray-700
">
Currently djlint will want to put all of the classes into a single massive class string. Can we get a config rule to not remove class newlines?
Good idea, prettier keeps them all in one chunk as well, and it also gets on my nerves when they are so long.
This would be such a quality of life improvement! 🙌
@TonisPiip @wgordon17 Hey, thanks for this. I'm thinking on doing one of several things. Can you let me know what you'd prefer?
I will add one new flag that will do one of the following:
- break classes when max line length is hit
- single class per line
- cluster x# of classes and then line break (for example, 3 classes per line etc)
or a better idea?
I don't think keeping existing line breaks will be an option here.
Some examples:
1
max line 120:
<a
href="foo"
class="
inline-flex items-center p-4 another class something inline-flex items-center p-4 another class something something
bg-white hover:bg-gray-200 blah blah ok another class bg-white hover:bg-gray-200 blah blah ok another class asdf
text-sm font-medium text-gray-500 hover:text-gray-700 text-sm font-medium text-gray-500 hover:text-gray-700
">
2
this is a mess
<a href="foo"
class="
inline-flex
items-center
p-4
another
class
something
inline-flex
items-center
p-4
another
class
something
something">
3
this is maybe cool
three classes per line
<a
href="foo"
class="
inline-flex items-center p-4
another class something
inline-flex items-center p-4
another class something
something bg-white hover:bg-gray-200
blah blah ok
another class bg-white
hover:bg-gray-200 blah blah
ok another class
asdf text-sm font-medium
text-gray-500 hover:text-gray-700 text-sm
font-medium text-gray-500 hover:text-gray-700
">
3 also lets us do # 2 :)
Hmmm... none of the above?
- Kinda OK, but doesn't allow grouping by
- Jesus Christ no, that's too much
- Looks the best, but the still doesn't preserve the grouping that the developer wrote.
Can we just preserve the user chosen number and placement of linebreaks, and just indent them to match?
so
<a
href="foo" class="flex items-center p-4
bg-white hover:bg-gray-200
text-sm font-medium text-gray-500 hover:text-gray-700">
->
<a
href="foo"
class="flex items-center p-4
bg-white hover:bg-gray-200
text-sm font-medium text-gray-500 hover:text-gray-700"
>
That works for organized developers, but what about messy guys like me who just copy and paste junk and hope it gets formatted? 😁
Maybe if we sort them and group by letter? Something like if I have class="px-12 bg-white grid border gap-2 ml-12 pl-2"
it would do. I do think that as like this it is a bit too dependent on the tailwind conventions :sweat_smile:
class="bg-white border
gap-2 grid
ml-12
pl-2 px-12"
@aalekseev cool idea 🚀 but yeah probably too tailwindy... we must be getting closer to the answer tho
I like the sorting, by alpha, but that's very TW dependtant, and should be an optional option.
But if we're talking about things which aren't classes, just any multi-line attrebute, I suspect that indentation isn't going to effect anything, but putting things into multiple lines at "random" places might. For example when using hyperscript.
I feel that the native approach (or a bool in config) should be that is doesn't remove or add \n
s in tag attributes, just indents them to the same level of the tag key (class
or _
or whatever)
And once that's done, things will look pertty normal, even if it's a messy copy-paste. And if we want, we can have another option which is just for class
that can have "max-len, max num, sorted" options.
I feel this linter/formater doesn't need to be black levels of unflexable opinionated formating, as we already have options for if newlines should be after an {% endblock %} for example.
That reminds me, there should be an option (or by default) that if there's a {% block %} in a attribute, it shouldn't add the newline, makes things quite funky, which is also kinda related to this, newlines inside values should be considered part of the value, other whitespace... not so much.
IMO, I think it feels more natural to match other configuration options, which are line-length based (max_attribute_length
and max_line_length
).
Also, having a break after X
number of classes might cause issues, especially with some classes potentially being insanely long 😱
@wgordon17 you are sugesting no new config option, just starting to wrap classes that are over the max attribute length/line length?
Well, that's an option...but I really just meant matching the existing configuration concept. I.e., create a max_class_length
(or something) that clips/wraps based on line length.
max_attribute_length
and max_line_length
are both good, but the core of this issue is to preserve (and indent) multi line class values without wrecking them.
hyperscript
Glad I'm not the only one having problem with how DjLint is formatting HyperScript.
This is how I write my Hyperscript (in data-script) and wish it to be preserved
<button type="button"
class="btn btn-light"
data-script="on click
remove .d-none .d-md-block from #nav
then add .d-none .d-md-block to #main
then add .d-none to #header">
show nav
</button>
This is currently how its being formatted. FYI using Vscode with DjLint extension.
<button type="button"
class="btn btn-light"
data-script="on click remove .d-none .d-md-block from #nav then add .d-none .d-md-block to #main then add .d-none to #header">
show nav
</button>
Hey, following back up this.
I'm thinking I will add 2 flags:
- --preserve-attribute-breaks
- not sure yet... something about max elements/line... tbd if more ppl comment here. I will leave the issue open for that.
Would love to revive this! Using AlpineJS so not uncommon to have long data-attributes. I think a flag for '--preserve-attribute-breaks' makes sense as auto-wrapping could lead to some issues that depend on formatting?
I use AlpineJS extensively and properties like x-data and x-init that I often put on multiple lines are forced on one line by djlint. Would be awesome if this was either left alone (or even better, formatted nicely by djlint :smile: ).
I know this issue is about more than simply tailwind, but it would also be amazing if we could mimic the functionality of prettier-plugin-tailwindcss! Their plugin enforces a strict ordering of classes based on the layer it comes from. I was considering writing a custom linter rule to at least check if they're out of order, but ideally the formatter would be able to fix any errors.
What's the status on this, do we have some consensus on what feature(s) are should be included? It does seem like it should be always a opt-in feature, but I'm not seeing any progress on this.
I might want to take a stab at it, if we can get a agreement of what we want, so that there's no argument after the work is done.
@lukfal94 +1 for the prettier-plugin-tailwindcss feature of ordering classes. Is there a plugin system in djlint? How could we achieve that?
My current solution is to disable formatting for hyperscript code
<select name="menu"
id="id_menu"
{# djlint:off #}
_="on change
if my value is 1
then remove @disabled from #id_food
else add @disabled to #id_food
end"
{# djlint:on #}
>
<option value="1">Menu 1</option>
<option value="2">Menu 2</option>
<option value="3">Menu 3</option>
</select>
<select name="food" id="id_food">
<option value="1">Food 1</option>
<option value="2">Food 2</option>
<option value="3">Food 3</option>
</select>
I wonder what is the status of this issue? Or if there are any plans on implementing something to handle tailwind classes and alpine.js attributes?