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

Clarify status of class:directive #15112

Open
cloudymeatball opened this issue Jan 25, 2025 · 6 comments
Open

Clarify status of class:directive #15112

cloudymeatball opened this issue Jan 25, 2025 · 6 comments

Comments

@cloudymeatball
Copy link

Describe the bug

Currently, the docs on svelte class directive state:

Unless you’re using an older version of Svelte, consider avoiding class:, since the attribute is more powerful and composable.

Upon requesting the cli maintainers to work on a migration script, the svelte team member said that perhaps the docs is pushing the new syntax a bit too much and may require clarification.

As I do not have the data or heuristics to know if and when there is noticeable differences in performance or DevEx, it seems best for a maintainer to edit the docs in one or two sentences to clarify the future of class:directives, performance gains/losses, and whether this is opt-in or the new norm.

A starting point could be

You can opt-in to the more powerful and composable attribute syntax above. There is currently no plan to deprecate the directive syntax.

Reproduction

N/A

Logs

System Info

N/A

Severity

annoyance

@sacrosanctic
Copy link
Contributor

#15113 (comment)

@Rich-Harris
Copy link
Member

class: will eventually be deprecated, because it's better to have a single way of doing things, and because class={...} avoids various drawbacks of class: — lack of composability, ambiguity around ordering, difficulty controlling multiple classnames from a single value, loss of readability when class="..." and class: are visually separated, etc.

We haven't done so yet, because class: is widely used in the wild and it would create a lot of terminal spam if the compiler started warning about it today. We need a migration script before we can do that. (I missed the discussion that @manuel3108 referred to in the linked issue, but I think I would have reached a different conclusion — if nothing else I'd like to use the migration script, though I haven't had any time to work on it myself.)

For now the docs are focused on encouraging people to use class={...} for new code, so the wording is intentional.

I know some people prefer class: for simple cases, so let me share some further thoughts (disclaimer: opinions expressed do not necessarily reflect the views of the Svelte team). Ultimately, you probably shouldn't be using dynamic classes in the first place. It's often tempting to do this sort of thing...

<nav>
  <a href="/" class:active={page.url.pathname === '/'}>home</a>
  <a href="/about" class:active={page.url.pathname === '/about'}>about</a>
</nav>

...but it's much better to do this:

<nav>
  <a href="/" aria-current={page.url.pathname === '/' ? 'page' : undefined}>home</a>
  <a href="/about" aria-current={page.url.pathname === '/about' ? 'page' : undefined}>about</a>
</nav>

Most of the time, there's an aria attribute or something else (like disabled) that you can use for styling that is also the more accessible/semantically appropriate option. For other cases, you can always use data- attributes — if we didn't need to demonstrate how class works in the tutorial, I wouldn't write code like https://svelte.dev/tutorial/svelte/classes, I'd do this instead:

<button
  class="card"
  data-flipped={flipped}
  onclick={() => flipped = !flipped}
>

Essentially, classes are supposed to describe what kind of thing something is. Other attributes describe the state of the thing. Put differently, class is a noun, everything else is an adjective. I recommend trying out this way of thinking; it feels pretty good.

The exception, of course, is Tailwind (and its imitators), where 'semantic HTML' is sneered at. If you're using Tailwind, you really do need dynamic classes. But the reason we added clsx is because class: doesn't work at all well with Tailwind, where you're frequently updating multiple classnames based on a single piece of state.

So if you're using Tailwind, you need class={...}. If you're not using Tailwind, you shouldn't really be using dynamic classes. Either way, there's very little genuine need for class:.

@sacrosanctic
Copy link
Contributor

The exception, of course, is Tailwind (and its imitators), where 'semantic HTML' is sneered at. If you're using Tailwind, you really do need dynamic classes

@Rich-Harris I don't believe semantic HTML and tailwind are mutually exclusive.

<nav>
  <a class="aria-[current=page]:text-blue-600" href="/" aria-current={page.url.pathname === '/' ? 'page' : undefined}>home</a>
  <a class="aria-[current=page]:text-blue-600" href="/about" aria-current={page.url.pathname === '/about' ? 'page' : undefined}>about</a>
</nav>

REPL

@Rich-Harris
Copy link
Member

You certainly can write Tailwind like that, though I'm not totally sure how common it is. Either way it's another situation in which there's no call for dynamic classes.

@Thiagolino8
Copy link

You certainly can write Tailwind like that, though I'm not totally sure how common it is

It's the official recommendation

@sacrosanctic
Copy link
Contributor

class: will eventually be deprecated

Why not explicitly say this in the docs? This is the case for other things in the docs.

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

Successfully merging a pull request may close this issue.

5 participants