Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Multi-line classes #495

Open
TonisPiip opened this issue Dec 23, 2022 · 22 comments
Open

[FEATURE] Multi-line classes #495

TonisPiip opened this issue Dec 23, 2022 · 22 comments

Comments

@TonisPiip
Copy link

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?

@christopherpickering
Copy link
Contributor

Good idea, prettier keeps them all in one chunk as well, and it also gets on my nerves when they are so long.

@wgordon17
Copy link

This would be such a quality of life improvement! 🙌

@christopherpickering
Copy link
Contributor

@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:

  1. break classes when max line length is hit
  2. single class per line
  3. 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 :)

@TonisPiip
Copy link
Author

TonisPiip commented May 9, 2023

Hmmm... none of the above?

  1. Kinda OK, but doesn't allow grouping by
  2. Jesus Christ no, that's too much
  3. 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"
> 

@christopherpickering
Copy link
Contributor

That works for organized developers, but what about messy guys like me who just copy and paste junk and hope it gets formatted? 😁

@aalekseev
Copy link

aalekseev commented May 9, 2023

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 😅

class="bg-white border
       gap-2 grid
       ml-12
       pl-2 px-12"

@christopherpickering
Copy link
Contributor

@aalekseev cool idea 🚀 but yeah probably too tailwindy... we must be getting closer to the answer tho

@TonisPiip
Copy link
Author

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 \ns 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.

@TonisPiip
Copy link
Author

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.

@wgordon17
Copy link

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 😱

@christopherpickering
Copy link
Contributor

@wgordon17 you are sugesting no new config option, just starting to wrap classes that are over the max attribute length/line length?

@wgordon17
Copy link

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.

@TonisPiip
Copy link
Author

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.

@firdaus-aziz
Copy link

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>

@christopherpickering
Copy link
Contributor

Hey, following back up this.

I'm thinking I will add 2 flags:

  1. --preserve-attribute-breaks
  2. not sure yet... something about max elements/line... tbd if more ppl comment here. I will leave the issue open for that.

@tristan-robinette
Copy link

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?

@krims0n32
Copy link

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 😄 ).

@lukfal94
Copy link

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.

@TonisPiip
Copy link
Author

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.

@lapinvert
Copy link

lapinvert commented Oct 4, 2023

@lukfal94 +1 for the prettier-plugin-tailwindcss feature of ordering classes. Is there a plugin system in djlint? How could we achieve that?

@firdaus-aziz
Copy link

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>

@franciscobmacedo
Copy link

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?

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

No branches or pull requests

10 participants