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

feat(module)!: use tailwind-merge for class merging #509

Merged
merged 8 commits into from
Aug 12, 2023

Conversation

benjamincanac
Copy link
Member

@benjamincanac benjamincanac commented Aug 7, 2023

The goal of this PR is to improve the DX when overriding components classes.

ui prop

Thanks to tailwind-merge, the ui prop is smartly merged with the config. This means you don't have to rewrite everything.

For example, the default preset of the FormGroup component is:

{
  "label": {
    "base": "block font-medium text-gray-700 dark:text-gray-200"
  }
}

If I want to change the font of the label, I would have to do this:

<UFormGroup name="email" label="Email" :ui="{ label: { base: 'block font-semibold text-gray-700 dark:text-gray-200' } }">

Now with the tailwind-merge, classes will be smartly merged so I can just write:

<UFormGroup name="email" label="Email" :ui="{ label: { base: 'font-semibold' } }">

Some breaking changes might occur where you've overridden the :ui prop, although it's unlikely as you'd rewrote the entire line anyway.

class

Still thanks to tailwind-merge, when using the class attribute on a component, those are now smartly merged with the classes computed from the ui prop and the app.config.ts.

When using for example a Badge component: <UBadge label="Badge" />, the classes generated looks like this: inline-flex items-center font-medium rounded-md text-xs px-2 py-1 bg-primary-500 dark:bg-primary-400 text-white dark:text-gray-900.

Let's say you want to change the font, you can do so through the ui prop: <UBadge label="Badge" :ui="{ font: 'font-bold' }" /> and this would work perfectly fine.

But, in some complex cases you might need to use the class attribute: <UBadge label="Badge" class="font-bold" />. This would result in those classes: inline-flex items-center font-medium rounded-md text-xs px-2 py-1 bg-primary-500 dark:bg-primary-400 text-white dark:text-gray-900 font-bold and wouldn't work as both font-medium and font-bold are present and font-medium has higher priority in the CSS stylesheet.

With this PR, the class attribute is merged and only font-bold will be present: inline-flex items-center rounded-md text-xs px-2 py-1 bg-primary-500 dark:bg-primary-400 text-white dark:text-gray-900 font-bold.

I apologize in advance as this might introduce a few breaking changes and is a bit of a step back from the previous versions:

  • In https://github.com/nuxtlabs/ui/releases/tag/v2.6.0, there was a breaking change on the Avatar component about class not being applied to the wrapper element anymore but to the img tag itself because of v-bind="$attrs" and inheritAttrs: false so you'd have to use :ui="{ wrapper: '...' }".
  • In https://github.com/nuxtlabs/ui/releases/tag/v2.4.0, there was a similar breaking change for all the form elements, this allowed to add listeners and extra attributes that we didn't add as a prop to the child input, radio, etc. tags. And if you look at the <input> documentation for example, there are plenty.

But after considerations I believe that when using the class attribute on a component, it should always apply to the wrapper HTML element and that overriding through :ui="{ wrapper: '...' }" can be a pain.

All the other attributes are still bound to the child HTML element, only class is being held on the wrapper

As class will no longer apply to the child element for Avatar, Checkbox, Input, Radio, Range, Select, SelectMenu and Textarea, a new prop has been added in each of those components. It is named after the target HTML tag:

  • img-class for Avatar
  • input-class for Checkbox, Input, Radio and Range
  • select-class for Select and SelectMenu
  • textarea-class for Textarea

Those props will also use tailwind-merge so you can override the computed classes of the HTML element

@vercel
Copy link

vercel bot commented Aug 7, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
ui ✅ Ready (Inspect) Visit Preview Aug 12, 2023 3:16pm

@nuxt-studio
Copy link

nuxt-studio bot commented Aug 7, 2023

Live Preview ready!

Name Edit Preview Latest Commit
ui Edit on Studio ↗︎ View Live Preview 35d95dd

@benjamincanac benjamincanac marked this pull request as ready for review August 7, 2023 16:17
@ZainW
Copy link

ZainW commented Sep 7, 2023

very appreciated change, thank you so much

@rambii
Copy link
Contributor

rambii commented Sep 19, 2023

Maybe worth noting this doesn't work in the app.config.ts (yet): see #628

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.

3 participants