Skip to content

Smarter formatting of HTML class attribute #7865

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

Merged
merged 12 commits into from
Jan 18, 2021

Conversation

thorn0
Copy link
Member

@thorn0 thorn0 commented Mar 24, 2020

Break classes onto multiple lines, but try keeping consecutive classes with the same prefix on one line.

fixes #7863

  • I’ve added tests to confirm my change works.
  • (If changing the API or CLI) I’ve documented the changes I’ve made (in the docs/ directory)
  • (If the change is user-facing) I’ve added my changes to changelog_unreleased/*/pr-XXXX.md file following changelog_unreleased/TEMPLATE.md.
  • I’ve read the contributing guidelines.

Try the playground for this PR

Sorry, something went wrong.

@thorn0 thorn0 force-pushed the smart-html-classes branch from 13a4c68 to a82a950 Compare March 24, 2020 21:52
foo
bar
foo
bar
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this looks not exactly good, but this is not a real-life example.

Copy link
Member

@fisker fisker Mar 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be real

Code from this github PR page

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like there is no good way to format this real example. Probably we should simply retain new lines in the class attribute, only re-indenting them if needed. That would be pity, the idea with prefixes looked good.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(from my perspective at least, the output in @fisker 's playground is great)

class="foo"
class="
foo
"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this is a printWidth: 1 test.

@thorn0 thorn0 force-pushed the smart-html-classes branch 2 times, most recently from 0f30eae to cd0956e Compare March 24, 2020 22:25
function getClassPrefix(className) {
let idx = className.search(/--|__/);
if (idx === -1) {
idx = className.indexOf("_");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about classes with a leading _?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

flex-column flex-lg-row
justify-content-start justify-content-lg-between
align-items-start align-items-lg-center
"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid we will get issues with requests to format each class on each line/don't touch, maybe we put information why we prefer it to docs?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid we will get issues with requests to format each class on each line/don't touch, maybe we put information why we prefer it to docs?

For me I prefer one name per line, also consider the following example:

<div class="custom-btn my-very-v-button--mini site-btn my-very-v-button--primary my-very-v-button--ghost">my button</div>

After running prettier, I got:

<div
  class="
    custom-btn
    my-very-v-button--mini
    site-btn
    my-very-v-button--primary my-very-v-button--ghost
  "
>
  my button
</div>

Given 80 as print width, the 3 names starting with my-very-v-button are actually able to fit into one line, but they are not, also it looks better to at least put them next to each other since they share the same prefix, i.e. switch the site-btn line with the last line.

So, my suggestion is let's don't group names with same prefix into one line, just let each name stands in it's own line(which is good for Git diff also), anyway an element or component that has more than 10 class names is really edge case, in that case I should consider my way of using class names, there must be some parts that can be improved to avoid too many class names on the same element.

Copy link
Member Author

@thorn0 thorn0 Jun 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maogongzi

the 3 names starting with my-very-v-button are actually able to fit into one line, but they are not

Right, because Prettier never reorders anything. However, one of the points of the current proposal is that in real projects, classes usually are already sorted by prefix, and when they are not, it's for a reason.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@evilebottnawi

I'm afraid we will get issues with requests to format each class on each line/don't touch, maybe we put information why we prefer it to docs?

I added an explanation to the changelog entry. Do you think we also need to write something in the docs about this?

@fisker
Copy link
Member

fisker commented Apr 24, 2020

All classnames in this PR page

@thorn0 thorn0 force-pushed the smart-html-classes branch from 272c88c to 338bcc2 Compare June 5, 2020 18:40
@maogongzi
Copy link

Any progress on this PR? Do we have a plan to merge it sometime? Up to now it's the only issue blocks me from upgrading Prettier to higher version.

@brody4hire
Copy link

bump

/cc @pburkindine

@thorn0
Copy link
Member Author

thorn0 commented Jan 18, 2021

Despite the low interest from the community let's give this a go...

@thorn0 thorn0 merged commit 7cf524f into prettier:master Jan 18, 2021
@thorn0 thorn0 deleted the smart-html-classes branch January 18, 2021 13:55
@alexcroox
Copy link

alexcroox commented May 10, 2021

Is there an easy way to disable this for classes? I've just upgraded and it's making my html templates pretty unreadable when using tailwind vs a wider single line of classes:

image

@ismailcherri
Copy link

This is going to be a nightmare for Tailwind CSS users

@sod
Copy link

sod commented May 10, 2021

I like the idea 👍. Given that we would never write 20 css instructions into a single line in a css file, I don't know how we accepted "minifying" the class attribute to begin with. Yes, it is verbose. But 20 class names is also very complex. I love the idea of grouping classes by prefix.

@slauzinho
Copy link

Is there a way of disabling this?

@thorn0
Copy link
Member Author

thorn0 commented May 10, 2021

It's not configurable. If #10803 gets implemented, it'll be possible to make a plugin to override this behavior.

@TomoyaKuroda
Copy link

We should have the option to disable this feature... this is still useful for some users though.

@cerpinn
Copy link

cerpinn commented May 15, 2021

This is being really annoying, disabling prettier for now.

P.S. I use TailwindCSS

@bodograumann
Copy link

Yeah, this is not working for us and the tailwind css classes.

First I thought I could maybe refactor the problematic instances to have fewer classes, but that doesn’t work either.
Having them inline is much easier to understand, than artificially refactoring into a class which is not actually reused.

My colleague is already giving me a hard time for automatically formatting with 80 character lines. 😞
Guess I’ll have to stay with prettier v2.2. It’s a pitty because I liked the other changes...

@KaragiannidesAgapios
Copy link

I'm going to downgrade to 2.2 for now.

I just want to add another problem that this feature introduces.
In my project we use vue test utils for testing.
Problem is that if you test for a classname existence:
expect(button.classes()).toContain('pointer-events-auto')

you get this result which evaluates to false:

Expected value: "pointer-events-auto"
    Received array: ["
    ", "", "", "", "", "", "", "", "", "", "pointer-events-auto
    ", "", "", "", "", "", "", "", "", "", "focus:outline-none
    ", "", "", "", "", "", "", "", "", "", "flex
    ", "", "", "", "", "", "", "", "", "", "items-center
    ", "", "", "", "", "", "", "", "", "", "text-gray-800
    ", "", "", "", "", "", "", "", ""]

Also if you try a workaround your test is not passing again:
expect(button.classes('pointer-events-auto')).toBe(true)
Console logging classes() you get the following result:

    [
      '\n',     '',                      '',
      '',       '',                      '',
      '',       '',                      '',
      '',       'pointer-events-auto\n', '',
      '',       '',                      '',
      '',       '',                      '',
      '',       '',                      'focus:outline-none\n',
      '',       '',                      '',
      '',       '',                      '',
      '',       '',                      '',
      'flex\n', '',                      '',
      '',       '',                      '',
      '',       '',                      '',
      '',       'items-center\n',        '',
      '',       '',                      '',
      '',       '',                      '',
      '',       '',                      'text-gray-800\n',
      '',       '',                      '',
      '',       '',                      '',
      '',       ''
    ]

This is the main reason that i will downgrade.
Indeed it's not optimal imo for tailwind users(i'm one) and it would be nice if this feature would be configurable.

Apart from that, thank you for your effort and have a nice day.

@j-f1
Copy link
Member

j-f1 commented May 19, 2021

That looks like a bug in vue-test-utils, @KaragiannidesAgapios. Specifically, this line should change to split on whitespace:

-let classes = classAttribute ? classAttribute.split(' ') : []
+let classes = classAttribute ? classAttribute.split(/\s+/gm) : []

@LeoniePhiline
Copy link

As a tailwind user, I would need this feature to be smarter. There simply aren't enough prefixes to be grouped. I would want classes to be grouped by domain (positioning, flexbox, spacing, ...), with one line per group.
This sounds like a job for a plugin, because semantic information is necessary.

Otherwise (as second best option), I'd really just want prettier to leave my classes alone and respect the newlines I add for my own grouping. Auto-indenting these groups is of course desired.

@prettier prettier locked as resolved and limited conversation to collaborators May 19, 2021
@alexander-akait
Copy link
Member

Please open an issue with example(s) where is bad, no need to write here, it was merged

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

P2.x - Group HTML classes by prefix instead of forcing onto one line