v3
benjamincanac opened this issue ยท 168 comments
We should start working on this next major by March, 2024.
I've started working on this in a private repository of mine, I'll open-source it once I'm satisfied with the base so you guys can check it out ๐.
You can check out the development progress in this fork: https://github.com/benjamincanac/ui3.
A lot has changed since @nuxt/ui
was made open-source (May 2023), so the plan here is to rewrite every component from scratch alongside their config.
I'll post regular updates on this issue and on https://twitter.com/benjamincanac.
Overview
- Tailwind v4 https://tailwindcss.com/blog/tailwindcss-v4-alpha which should solve #877
- #409 which should solve all
v3.0
issues - Switch our internal
useUI
for https://www.tailwind-variants.org/ - Inject theme in slots as shown here: 3a5db60#diff-8ebfa4604ad4706a0452993240719686c14ab8d3b81ebe15b1aa8201eb0282e3L4
- Generic components (migrate to
<script setup>
#818) - Remove safelists by compiling the theme on build based on pre-defined colors which should solve #889
- Tests are done while creating components (#1432 can't be merged because of dupe keys, this will be fixed by migrating to
<script setup>
) - Vue compatibility
Documentation
Once all these changes will be ready to merge on the dev
branch, a v2
branch will be created to keep supporting the v2
version for a certain period of time. As such, the current documentation will be available on https://ui-v2.nuxt.com
.
I'm thinking of removing the dev
packages from the documentation, not sure it's that useful as people who are checking new pull requests from GitHub can check the new docs inside the PRs content. Therefore, the documentation will deploy from the main
branch instead of the dev
branch.
Breaking Changes
The biggest change is the switch to tailwind-variants
, this will cause lots of breaking changes if you've used the ui
prop or app.config.ts
to override the config. I apologize in advance for this but I strongly believe this will be beneficial and will bring consistency across all components.
At the beginning the config was split in many keys for the same div to give more flexibility, but since then we introduced
tailwind-merge
which now allows us to group those keys together, this is a good opportunity to clean the whole thing.
The config will now have a slots
amongst other keys that will specifically target dom nodes. The ui
prop will only allow you to target those slots.
These changes alongside the refactor of all components will also improve the types, the app.config.ts
and ui
props are now perfectly typed, as well as all components props
, slots
, emits
and expose
.
Accordion
- Renamed
#item
slot to#content
for consistency - Removed usage of
UButton
underneath for a simple design easy to customize
Avatar
- Removed
chip
prop in favor ofChip
component
Button
- Removed
padded
prop block
prop no longer center the text but acts as a justify between to push the trailing icon
Divider
- Renamed to
Separator
for consistency
Dropdown
- Renamed to
DropdownMenu
for consistency
Form
New implementation of the Form component. Here's a list of notable changes from v2:
- Removed
submit
from the Form'svalidateOn
prop - Renamed
FormGroup
toFormField
- Renamed
path
toname
on form errors for consistency - Added
disabled
prop on theForm
component to disable the entire form - Added
validateOnInputDelay
prop onFormField
andForm
components to control the debounce delay on validation on input - Moved
validate
function's name argument to an option to make it optional - Nested Form components, allowing for complex forms with hierarchical validation
Thanks @romhml! ๐
Link
- Renamed exposed
isActive
toactive
in default slot
Toggle
- Renamed to
Switch
to be able to implement this: https://www.radix-vue.com/components/toggle.html - Renamed
on-icon
/off-icon
props tochecked-icon
/unchecked-icon
respectively
Popover
- Removed
overlay
prop as no primitive is available for this in Radix Vue - Removed
popper
prop in favor ofcontent
(https://www.radix-vue.com/components/popover.html#content) andarrow
prop - Renamed
#panel
slot to#content
for consistency
Tabs
- Renamed
#item
slot to#content
for consistency
Tooltip
- Removed
popper
prop in favor ofcontent
(https://www.radix-vue.com/components/tooltip.html#content) andarrow
prop - Added
#content
slot for consistency - Removed
prevent
prop in favor of:open="false"
Modal
/ Slideover
- Added
title
,description
andclose
props (this will deprecateDashboardModal
/DashboardSlideover
components in@nuxt/ui-pro
) - Removed
appear
prop (was for Headless UI)
VerticalNavigation
/ HorizontalNavigation
- Renamed to
NavigationMenu
with anorientation
prop - Removed
#icon
,#avatar
and#badge
slots in favor of#leading
and#trailing
for consistency
Feel free to comment on this if you have any ideas for the next major.
I would like to help, if I'm able to. Is there going to be a dedicated branch or will it be done in the dev
one?
Once we start this, there will be indeed a new branch with auto-release so we can try it out and especially keep working on the v2
as it might take some time. I'll create new issues once this gets started with the remaining things to do ๐
I have few design ideas if you are open to this I would like to share it for the future of Nuxt UI 3. Should we discuss this in this issue or it'll be better to discuss design ideas in seperate discussion thread?
@jd-solanki You can share them here!
Since it is supposed to be a refactoring to all components, could we give the possibility of compatibility with unocss?
@sawa-ko It will be made with Tailwind v4. To what end would you make it compatible with Uno?
I've started working on this in a private repository of mine, I'll open-source it once I'm satisfied with the base so you guys can check it out ๐.
A lot has changed since @nuxt/ui
was made open-source (May 2023), so the plan here is to rewrite every component from scratch alongside their config. For example, at the beginning the config was split in many keys for the same div to give more flexibility, but since then we introduced tailwind-merge
which now allows us to group those keys together.
I'll post regular updates on this issue.
Please tell me how long it will take for this upgrade to be available.
Very much looking forward to this upgrade
I have no idea how long it will take and it's not entirely up to us, I hope to release it at the same time as the official release of Tailwind v4.
That's awesome. The new version of nuxt-ui uses exactly the tech stack I expected.
I tried to build my own UI library using radix-ui and tailwind-variants, but I immediately found that even with radix-ui, it is not easy to build a full UI library.
But I got an idea with an API that works with any design language. If you are interested, here is my demo repository:
https://github.com/vincajs/vinca-ui
@robin-dongbin It's already in the making. There are already 13 components done, 36 more to go ๐
Since the component library is based on radix-ui without styles, I thought it would be nice to provide an api that is abstracted from various design systems, so you can switch styles from one system to another at any time.
If people want to implement another design system, they can just customize it, share files, or even contribute to a repository.
Taking things a step further, it is possible to switch between different design systems at runtime.
Of course, I'm just offering an idea, and if you think it's too late, that's fine
This is actually already what we're doing with the App Config. You can customize the classes for every part of every component.
Thanks for the work!
iโm impatient to try this!
Just one question :
The biggest change is the switch to tailwind-variants, this will cause lots of breaking changes if you've used the ui prop or app.config.ts to override the config.
app.config.ts
is deprecated and it will not port in v3? Or itโs something else?
No we keep the app.config.ts
, what I meant is since we now use tailwind-variants
the config itself changes.
For example the Kbd
component, its config looked like this:
export default {
base: 'inline-flex items-center justify-center text-gray-900 dark:text-white',
padding: 'px-1',
size: {
xs: 'h-4 min-w-[16px] text-[10px]',
sm: 'h-5 min-w-[20px] text-[11px]',
md: 'h-6 min-w-[24px] text-[12px]'
},
rounded: 'rounded',
font: 'font-medium font-sans',
background: 'bg-gray-100 dark:bg-gray-800',
ring: 'ring-1 ring-gray-300 dark:ring-gray-700 ring-inset',
default: {
size: 'sm'
}
}
Here is the new version:
export default {
base: 'inline-flex items-center justify-center text-gray-900 dark:text-white px-1 rounded font-medium font-sans bg-gray-50 dark:bg-gray-800 ring ring-gray-300 dark:ring-gray-700 ring-inset',
variants: {
size: {
xs: 'h-4 min-w-[16px] text-[10px]',
sm: 'h-5 min-w-[20px] text-[11px]',
md: 'h-6 min-w-[24px] text-[12px]'
}
},
defaultVariants: {
size: 'sm'
}
}
This is a breaking change if you've overridden its config in your app.config.ts
or through the ui
prop. I'm thinking of a CLI or something that would help people migrate from v2
to v3
without too much trouble but it might not be easy to achieve. Everything is fully typed so this will give some indications at least.
Ok !
Effectively, it's a breaking change but it seam ok for the future to have a better granularity with the variants.
Thanks for the explanation and the example ๐๐ป
Here are some thoughts on the new version:
VerticalNavigation
/HorizontalNavigation
should beNavigationMenu
with anorientation
propNotification
should rename to 'Toast', now we haveNotification
component and 'useToast' function, that is confused. and for new version I hope we support runtime placement.Table
should be a simple wrapper of primitivetable
no more features. (Building a complete data table is very complex)- As an alternative provide a
DataTable
component for more complex usage. Recommended use https://github.com/TanStack/table. InputMenu
rename toAutocomplete
SelectMenu
rename toCombobox
. In fact, I recommend the same naming for everything as radix, which makes more sense.
This is actually already what we're doing with the App Config. You can customize(่ชๅฎไน) the classes for every part of every component.
I think the API I envision is better in this regard.
Because you can provide multiple design system presets in the repository for users to choose from, switching styles is easy.
For now, of course, you can just provide one preset, nuxt style
But it does reserve an easier way to extend it to implement more design systems.like Material Design
, Ant Design
and so on
I agree with everything @robin-dongbin said, except for the Table I am not sure about this one.
Notification should rename to 'Toast', now we have Notification component and 'useToast' function, that is confused. and for new version I hope we support runtime placement.
Otherwise useToast()
could be named useNotification()
instead. I mean why is it named toast in the first place? I am not a native english speaker but I couldnt find another translation for toast than the bread (toast is not actual bread but you know what I mean).
@MickL Toast
is widely used in UI/UX for a quick message that shows up and then disappears, just like how toast pops out of a toaster when it's ready.
In Radix the component name is Toast
https://www.radix-vue.com/components/toast.html
Hello,
I'm really sorry but decision to use radix vue
is the worst thing happening to this library. It will be a pain in the future for sure.
I don't like how tailwind team abandoned silently headless-ui
but at least it's being supported and proven to work without much issues.
You shouldn't be relaying on the library that has over 33 open issues and the author doesn't even know how to fix some issues.
Just my 2 cents.
@divine I'm sorry but I completely disagree with you, @zernonia has been doing an amazing job on Radix Vue with weekly releases https://github.com/radix-vue/radix-vue/releases, 33 issues is nothing for a UI library.
@robin-dongbin Thanks for the suggestions! Regarding the NavigationMenu
component replacing VerticalNavigation
and HorizontalNavigation
, do you think it should use https://www.radix-vue.com/components/navigation-menu.html underneath?
As for the Table
component, as mentioned in #653 I'll try @tanstack/vue-table
.
What is your suggestion for the preset system?
I'm not sure about the InputMenu
/ SelectMenu
rename though as the Combobox
is a primitive that will be used in multiple components like CommandPalette
much like the Dialog
being used in Modal
and Slideover
.
@divine I'd argue that Nuxt UI adopting Radix Vue will make Radix Vue even better and in turn Nuxt UI, benefitting both. Also, most issues are feature requests and not bugs (7 out of 33)
@messenjer thanks for clarifying! I would still propose to rename useToast()
to useNotification()
as it is way more clear than the image of a jumping toast.
P.S. I am very excited for v3 :)
Also my view on the naming of "notifications". There is also the browser's notification for desktop/mobile notifications.
Some could argue that this would be confusing as well.
VueUse named it useWebNotification so the imports do not conflict but still...
I think I will rename it to Toast
to match Radix Vue component as suggested by @robin-dongbin and keep useToast()
. This prevents any breaking change as you don't have to instantiate this component yourself.
Also my view on the naming of "notifications". There is also the browser's notification for desktop/mobile notifications. Some could argue that this would be confusing as well. VueUse named it useWebNotification so the imports do not conflict but still...
It is not named browser toasts tho, as well as notifications on the desktop or smartphone are not named toast. They are all notifications and toast is confusing imo :)
@benjamincanac Yes, I mean to use https://www.radix-vue.com/components/navigation-menu.html under the hood
In fact, I think if radix provides relevant components, I think we should use the components provided by radix as much as possible to obtain better accessibility and reduce the maintenance burden.
On the basis of ensuring the implementation of all the components provided by radix, we should build some basic components that radix does not provide, such as Button
, Input
etc., as well as combined components based on the combination of basic components and radix components, such as Drawer
After that, I don't know if radix plans to provide more advanced components. Like Datatable
,Uploader
, After all, they just provided the Calendar
,In my opinion, this is an advanced component. All the advanced components I think mean complexity. It takes a lot of time to build such components. If radix does not plan to provide them, maybe we can choose mature open source third-party headless components. Such as tanstack/vue-table.
About the preset system, That's what I said above. I tried to make a demo myself. https://github.com/vincajs/vinca-ui, just has a few base component, But it can already explain the api to you that I imagined. If you are interested, just take 2 minutes to check the repository.
@jd-solanki You can share them here!
Thanks, I'll write everything I have in mind for Anu v1 and as Nuxt UI 3 is going to use Radix I don't want to write another lib that does the same thing. Below list will also have my own thoughts & opinions so feel free to discuss or skip them.
- Along with components like
Alert
that has props likeicon
,title
,description
if we provide low level components likeAlertTitle
,AlertDescription
as well that will cover all the cases like we might want alert with some weird or special structure in other parts of site like landing pages. You can even consider collapsible component which can be used in admin side and also completly differently on landing pages for FAQ. - Supporting above point, Providing component locally like shadcn will make users of the lib adopt the lib. Here's why: We built admin templates and we're now going for RadixVue but we decided to go fo Shadcn for now instead of nuxt UI because in worst case scenario if the bug or issue come up we can fix that locally and make a new release without relying on third party lib. Another case can be, We may want some change that lib author might not prefer adding to their own lib so in this case having component locally can also benefit both user of the lib and lib author. I strongly support this point and would love to see local components with Nuxt UI 3.
- Naming & Component API should be carefully picked considering future CSS & HTML updates to avoid introducing breaking changes after v3 release. For example, we're discussing about toast & notification. Another example is chip, If you ask me it's better named as badge instead of chip because chip is generally like this (Chip & badge are two different things and can co-exist).
- In case of breaking changes we can use soft deprecation to avoid more work for users.
You can also read my thoughts here.
Unfortunately, I donโt have enough time these days to fully contribute to the v3 project. However, if you are willing to provide components locally, I would be more than happy to help in any way I can.
What do you guys think of removing the USelect
in favor of USelectMenu
(would be renamed to USelect
)? Is there some cases where we specifically need native <select>
?
Questions I have on this:
- Is the
USelectMenu
just as accessible as the native<select>
? - What about mobile? I like to have select menu's native behaviour on mobile if I don't need any styling. Do we lose this?
- Do you think having something like a prop (
<USelect native>
) would be a good idea? Does it make sense?
Mostly the mobile behaviour is what concerns me a little.
If we use the Select
from Radix Vue, it will be accessible yes: https://www.radix-vue.com/components/select. It renders an hidden <select>
underneath. You can take a look on mobile how it behaves.
Not sure how we can handle the search with this though.
It would be great if Modal will have some variants like small, medium, large, fullscreen. Currently it is very cumberstone to change the width of it.
@MickL You can actually change the width quite easily by using :ui="{ width: 'sm:max-w-xl' }"
, in v3
you will even be able to do this directly with class
.
I know but it would be nice to have some options like small, medium, large, fullscreen. It is the same as you would say we can change color of a button easily but it is nice to have color and variant props.
wow! vue compatibility, thanks for the work!
How about rename leading
and trailing
to prefix
and suffix
. This is how most UI libraries are named
Just a small thought: with the radix-vue implementation, is it planned to drop popperjs? This was discussed in #409(comment) but not updated here
It's implicit yes as Radix Vue uses Floating UI underneath (the new version of popper) so we don't have to.
@sawa-ko It will be made with Tailwind v4. To what end would you make it compatible with Uno?
Because it can be done.
Because UNOCSS is better.
Because it was created by a member of the nuxt team.
When is the expected release of the new version?
Do you intend to implement virtual scroll for UTable
or you gonna leave it to the users to decide how they want to do it?
Thanks for the amazing work I was coming here to suggest a better config setup and I found it was already changed to a better one!
I'd like to suggest also integrating tailwindcss-animate plugin.
It would be nice if Tailwind CSS v4 had plugins ๐ We'll have to wait and see how they implement it.
Oh you're right forgot about that
What do you guys think of removing the
USelect
in favor ofUSelectMenu
(would be renamed toUSelect
)? Is there some cases where we specifically need native<select>
?
The new USelect must allow group management (as <optgroup> native element) ;-) available in https://www.radix-vue.com/components/select
Can ui 2.x.x be upgraded to ui 3.x.x?
Can ui 2.x.x be upgraded to ui 3.x.x?
Yes, but not without some effort from your part.
Breaking changes are listed at the initial post.
Just a thought ( you could ignore it if it's out of scoop) But it would't be great to have a switch for Styled / Unstyled components as Primevue did ?
@Celibioux I guess this would technically be possible but I'm wondering what would be the benefit here. If you'd have to rewrite the entire config, why not write the component yourself by using radix-vue
directly for example?
One thing I've been struggling with: consistent rendering of rich text content within components. Mainly pulling from YML content files. For example, I want a bolded word in the primary text colour within the title of a particular UI component.
It would great to have minimal markdown support without having to override slots and use the <MDC>
component. Though perhaps that's not a good default, so maybe some sort of config option to trigger when this happens?
Even when overriding slots and using the <MDC>
component explicitly there's one problem that occurs a fair bit: since the MDC component always wraps the content in a <p>
tag it often happens that this ends up with invalid HTML from the server (e.g. this markdown generated <p>
tag is now within a <p>
tag because that component's slot is wrapped in a <p>
tag already). This results in a hydration error on the client. So I've ended up sometimes having MDC components, and sometimes using v-html
, in overridden slots, which is unfortunate (and messy).
(Apologies if this is the wrong place to put this โ I'm happy to split this out into a separate issue / discussion).
Thanks @benjamincanac for the quick response. Great to know it's on your radar.
I agree that replacing <p>
tags automatically with <div>
is not the best solution. One way I've tackled this before (when consuming content from a CMS) is to allow the developer of the template to configure which element (if any) to use as the wrapper. I guess this is more a feature request for https://github.com/nuxt-modules/mdc โ I'm thinking the <MDC>
component already has the tag
prop, so you could introduce a contentWrapperTag: string | false
prop as well, to define what the markdown parser should do.
Just to say: I'm making extensive use of Nuxt UI (and UI Pro) and loving it! Keep up the amazing work.
This commit 49b73aa made me think that NuxtUI could automatically use <NuxtImage>
if installed and fallback to <img>
otherwise
I was hesitant about do a PR to add a UImg component which returns either an img or nuxtimg element depending on whether the nuxt image module is present.
@benjamincanac thanks for your quick answer and you're right but the idea came from seen many folks ask for unocss integration so unstyled could be possible to use unocss for styling ? And Yes there is Radix_vue and many out there but We Are NUXTERS ๐ We Love Nuxt and All its Ecosys
@benjamincanac thanks for your quick answer and you're right but the idea came from seen many folks ask for unocss integration so unstyled could be possible to use unocss for styling ? And Yes there is Radix_vue and many out there but We Are NUXTERS ๐ We Love Nuxt and All its Ecosys
The preset api I mentioned above solves this problem as well. It decouples nuxt-ui from tailwindcss, giving the user the freedom to use any css tool of their choice to provide the styles.
The ui library can even remove the tailwindcss dependency and only provide tailwindcss presets, allowing the user to install the taiwindcss dependency and compile the presets on the user side.
Official presets can provide classes compatible with tailwindcss and unocss. The user is free to choose either unocss or tailwindcss.Even if they prefer another css tool, they can completely redefine their styles using another css tool.
I've been pitching the preset api I came up with, but @benjamincanac don't seem to be interested ๐ .
I believe what @robin-dongbin is saying about the presets is very similar to what Shadcn UI does with the "default" and "New York" theme to change the appearance of every component. Maybe something like this could exist for Nuxt UI, but I'm not sure, since Shadcn does that by giving you the files for each component.
However, I agree with @benjamincanac saying that if you already intend to use Nuxt UI completely unstyled, try using Radix Vue to build the components yourself. You might find that very useful.
Radix Vue gives you full control over the styling of your components, while providing accessibility and the complex logic of the components for free. Use vanilla CSS, Tailwind, UnoCSS... whatever you consider best.
Nuxt UI is meant to give you good looking, opinionated and pre-styled UI components, but expose the API to customize them when needed. And in my opinion, it does it wonderfully.
I invite you to take a look at Radix Vue to build your own components if you apply to any of the following:
- You end up changing the UI of almost every component to match your branding.
- You don't agree with the choices for the stack (Tailwind, TanStack Virtual, etc.).
- You need a component that is not currently offered by Nuxt UI.
- You need to add custom logic/behavior to your components internally.
I won't lie... It can be significantly more work. But it is worth it if you really need it.
@ChrisGV04 Thank you for your time replying on this really great answer
I forgot to mention that the repository we're working on is public if you want to check out the progress: https://github.com/benjamincanac/ui3.
The development is going very well, we're only missing 12 components and I can say that maintaining this version will be significantly easier. Also, contributing will be effortless with the internal CLI we created to initialize components: https://github.com/benjamincanac/ui3/blob/dev/cli/templates.mjs.
I can't wait to finally release this ๐
I forgot to mention that the repository we're working on is public if you want to check out the progress: https://github.com/benjamincanac/ui3.
The development is going very well, we're only missing 12 components and I can say that maintaining this version will be significantly easier. Also, contributing will be effortless with the internal CLI we created to initialize components: https://github.com/benjamincanac/ui3/blob/dev/cli/templates.mjs.
I can't wait to finally release this ๐
Awesome work โค๏ธ
What about Vue compatibility
? Will we definitely see it in the next major release?
I was hesitant about do a PR to add a UImg component which returns either an img or nuxtimg element depending on whether the nuxt image module is present.
@benjamincanac I added something similar on @nuxtjs/mdc
https://github.com/nuxt-modules/mdc/pull/180/files
Would it be possible to update UAvatar
to be compatible with masks in v3? The Squirqle mask looks amazing! ๐คฉ
I feel like this isn't currently possible with a chip #1627
Nuxt Icon beta implements the offline usage from iconify and supports SSR. Will it be integerate in v3 and drop egoist/tailwndcss module? It already does
VerticalNavigation
/HorizontalNavigation
should beNavigationMenu
with anorientation
prop
I whish that component (especially on orientation="vertical"
had some way to keep the NavigationMenuSub
expanded when its submenu item is active. For context radix-vue/radix-vue#892
Even better if NuxtUI would have the vertical navigation similar to the one on Naive UI or Ant Design