🎨 Allow replacing all UI classes with new set of classes?
Package
v4.0.0-alpha.x
Description
Hi 👋🏻
I was using PageHeader component and I wanted to heavily customize it for my starter-kit. For this I have to write the same class with media query variant to ensure that existing class doesn't apply to my customized component.
E.g. I wanted to reduce the font size of the heading and for that I had to write same class twice:
pageHeader: {
slots: {
title: 'text-xl sm:text-xl',
},
},
It'll be easy if we can provide a way to replace current classes entirely via something like this:
pageHeader: {
slots: {
title: (existingClasses) => 'text-xl font-bold text-pretty',
},
},
With this user can completely omit the existing style and apply our own style. This wasn’t particularly relevant to components, but as we ship block-like components, it becomes relevant to customize them heavily and override the existing style.
Additional context
No response
I may have misunderstood, but I don't see why it can't already be done in app.config.ts 🤔
Hey @HugoRCD
Glad to talk to you. Default classes for UPageHeader title is text-3xl sm:text-4xl text-pretty font-bold text-highlighted. Now, I want simple header having two classes: text-xl font-bold.
So when I try something like this:
pageHeader: {
slots: {
title: 'text-xl',
},
},
It'll merge all classes and I will endup with following: text-xl sm:text-4xl text-pretty font-bold text-highlighted. As you notice we still have sm:text-4xl which will render large 4xl fonts in desktop devices and for that I need to duplicate the same class for sm breakpoint like this:
pageHeader: {
slots: {
title: 'text-xl sm:xl',
},
},
Now this will result in text-xl sm:text-xl text-pretty font-bold text-highlighted. Notice we have duplicate text-xl style and also I don't want other classes like text-highlighted.
Hence, if we can introduce new feature where user can provide function and return value will be final class list instead of merging them.
pageHeader: {
slots: {
title: () => 'text-xl font-bold',
},
},
Now Nuxt UI will identify that this is function and instead of merging we'll directly take return value of the function as class value and I'll have only these two classes text-xl font-bold for my UPageHeader. This will allow us customize components easily.
@jd-solanki You can use !text-xl to apply this style across all breakpoints !
Ya, And then to remove text-pretty I have to write another class. Getting my point? Basically, I had to revert all the classes which I don't need. Assume something has 7 classes and I want only 2 then I had to revert 5 classes.
But anyway, this is just proposal and incident I faced today. Feel free to mark this as not planned.
@jd-solanki I've already tried to implement this back then but unfortunately tailwind-variants doesn't support this when extending: https://github.com/nuxt/ui/blob/v4/src/runtime/components/Button.vue#L103
@jd-solanki I have a similar problem. I'm trying to style hover on table rows, which brings me to these definitions, which are quite hard to override (e.g. via <UTable :meta="{ class: { tr: row => 'something' } }")
tbody: 'divide-y divide-default [&>tr]:data-[selectable=true]:hover:bg-elevated/50 [&>tr]:data-[selectable=true]:focus-visible:outline-primary',
tr: 'data-[selected=true]:bg-elevated/50',
@benjamincanac I noticed that tailwind-variants doesn't support overriding when extending. How about to override before the actual extend operation with the configuration similar to this:
export defineAppConfig({
ui: {
// Override
override: {
table: { slots: { tbody: 'override' } },
},
// Normal extend
table: { slots: { tbody: 'extend' } },
}
})
Which would then result in: <tbody class="override extend">
I know it might be a little bit ecclectic, but it would be really nice feature to have a chance to override default styles, even if it's just in defineAppConfig.
I also second this. This overriding used to exist pre v3 and was changed to merging which I agree usually makes more sense, but when customizing having to negate a bunch of rules is not nice.
@benjamincanac should we reopen this or not planned at all?
We can reopen but I still have no clue how to achieve this unfortunately 😬
I'm not that familiar with tailwind variants, looking at the code, maybe something like this where stripOverrides will return a version of the theme with styles removed when the app config has something like this?
comp: {
strategy: {container: "override"},
slots: {
container: "only these classes will ever appear",
},
},
const ui = computed(() => tv({ extend: tv(stripOverrides(theme), appConfig.ui?.comp), ...(appConfig.ui?.comp || {}) })({
}))
Or could it be done at the theme level somehow. I see they are passed options somehow: export default (options: Required<ModuleOptions>) => ({
The problem is critical for complete redefinitions. For example, I need to completely redefine the inactive position style. I'm having trouble doing this.
export default defineAppConfig({
ui: {
commandPalette: {
variants: {
active: {
false: {
item: [
'text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50',
'transition-colors before:transition-colors',
],
},
},
},
},
},
})
Can anyone tell me how to remove the highlighting - the background change when hovering the mouse over a position - without breaking everything?