Skip to content

feat(Theme): add variants prop#6031

Draft
Bobakanoosh wants to merge 4 commits intonuxt:v4from
Bobakanoosh:feat/theme-variants
Draft

feat(Theme): add variants prop#6031
Bobakanoosh wants to merge 4 commits intonuxt:v4from
Bobakanoosh:feat/theme-variants

Conversation

@Bobakanoosh
Copy link
Copy Markdown
Contributor

@Bobakanoosh Bobakanoosh commented Feb 13, 2026

Resolves #6359

❓ Type of change

  • 📖 Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • 👌 Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

Follow-up to #4387, adding a variants prop to UTheme as discussed.

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@github-actions github-actions Bot added the v4 #4488 label Feb 13, 2026
@Bobakanoosh
Copy link
Copy Markdown
Contributor Author

@benjamincanac Here is a POC of the variants prop on UTheme, I pushed an example in the button playground.

Seeking guidance on the following, the types are a bit tricky:

  1. Passing this variant configuration to useFieldGroup
  2. Passing this variant configuration to useComponentIcons

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 13, 2026

📝 Walkthrough

Walkthrough

This change introduces a new variant theming system for components by adding a useComponentVariant composable that enables components to derive variant overrides from theme context. The Theme component is extended to provide variant context alongside UI context, with the ui property made optional. The Button component is updated to use the new variant composable to source variant values from the theme context instead of directly from props. A playground example is updated to demonstrate the new UTheme wrapper with variant and UI configuration.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into v4
Description check ✅ Passed The PR description clearly references issue #6359 and explains it as a follow-up adding a variants prop to UTheme, which aligns with the changeset showing new variant context support across multiple files.
Title check ✅ Passed The title 'feat(Theme): add variants prop' accurately describes the main change — adding a variants prop to the Theme component. It is concise, specific, and clearly summarizes the primary objective of the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/runtime/composables/useComponentVariant.ts`:
- Around line 32-39: The computed in useComponentVariant currently merges theme
overrides with props.variants which doesn't exist, so component props (e.g.,
color, variant) are ignored and not tracked; update the merge to use the actual
props object (e.g., defu(props, themeOverrides)) so explicit props take
precedence and Vue reactivity tracks prop changes inside the computed returned
by useComponentVariant; optionally, to reduce over-tracking, pick only the
variant-related keys from props before calling defu.
🧹 Nitpick comments (1)
src/runtime/components/Theme.vue (1)

20-26: Consider whether nested <UTheme> should merge contexts.

Currently, each <UTheme> fully replaces both the UI and variant contexts for its descendants. If a user nests <UTheme :variants="{ button: { color: 'red' } }"> inside <UTheme :variants="{ button: { variant: 'soft' } }">, the inner theme will lose the outer's variant: 'soft'.

This may be intentional for a POC, but worth considering whether defu-merging with the parent context (similar to how useComponentVariant merges props with theme overrides) would provide a more intuitive cascading behavior.

Comment thread src/runtime/composables/useComponentVariant.ts Outdated
@benjamincanac benjamincanac changed the title feat(UTheme): variants poc feat(Theme): add variants prop for component theming Feb 15, 2026
@benjamincanac benjamincanac marked this pull request as draft February 16, 2026 11:59
@Bobakanoosh
Copy link
Copy Markdown
Contributor Author

@benjamincanac Any feedback on this POC? Would love to proceed with implementing on all components.

Still Seeking guidance on the following, the types are a bit tricky:

  • Passing this variant configuration to useFieldGroup
  • Passing this variant configuration to useComponentIcons

@caiotarifa
Copy link
Copy Markdown
Contributor

We really need this.
Thank you for your work, @Bobakanoosh.

@benjamincanac
Copy link
Copy Markdown
Member

@Bobakanoosh Will look into it asap!

@benjamincanac benjamincanac changed the title feat(Theme): add variants prop for component theming feat(Theme): add variants prop Apr 21, 2026
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 21, 2026

npm i https://pkg.pr.new/@nuxt/ui@6031

commit: d7b5565

@benjamincanac
Copy link
Copy Markdown
Member

@Bobakanoosh I pushed some improvements on top of your work to unify theme context.

However, before rolling out to all components, I want to think about the broader direction. Right now variants only overrides TV styling variants (color, variant, size). But looking at #2662 and how Vuetify does it with their defaults provider, we could go further and let UTheme override any prop on any component, like <UTheme :tooltip="{ arrow: true }"> or <UTheme :accordion="{ collapsible: false }">.

A few open questions:

  1. Should UTheme have per-component props (:button, :tooltip) instead of a single nested variants object?
  2. Should UTheme only handle contextual/scoped overrides, and global app-wide defaults (Override default props from AppConfig #2662) live on UApp instead?

Thoughts? cc @sandros94 @jd-solanki

@sandros94
Copy link
Copy Markdown
Member

@Bobakanoosh I pushed some improvements on top of your work to unify theme context.

However, before rolling out to all components, I want to think about the broader direction. Right now variants only overrides TV styling variants (color, variant, size). But looking at #2662 and how Vuetify does it with their defaults provider, we could go further and let UTheme override any prop on any component, like <UTheme :tooltip="{ arrow: true }"> or <UTheme :accordion="{ collapsible: false }">.

A few open questions:

1. Should UTheme have per-component props (`:button`, `:tooltip`) instead of a single nested `variants` object?

2. Should UTheme only handle **contextual/scoped** overrides, and global app-wide defaults ([Override default props from `AppConfig` #2662](https://github.com/nuxt/ui/issues/2662)) live on UApp instead?

Thoughts? cc @sandros94 @jd-solanki

My personal gut feeling is your second option: a clear separation between the overrides from the global configs (UTheme and UApp respectively)

@benjamincanac
Copy link
Copy Markdown
Member

@sandros94 So you think we should keep UTheme only to override ui props and default variants props like color, variant and size?

@sandros94
Copy link
Copy Markdown
Member

@sandros94 So you think we should keep UTheme only to override ui props and default variants props like color, variant and size?

@benjamincanac yes indeed

@Bobakanoosh
Copy link
Copy Markdown
Contributor Author

@benjamincanac @sandros94

I don't see why not both - the problem UTheme solved was that the global theme configuration was not enough - we needed theming scoped to subset of the component tree.

The same could potentially be said for component prop defaults.

I'd propose:

<UTheme
    :ui="..."
    :variants="..."
    :components="{
         tooltip: {
              delayDuration: 150
         }
    }"
>
...
</UTheme

@benjamincanac in reference to your 1 option:

Should UTheme have per-component props (:button, :tooltip) instead of a single nested variants object?
variants does not serve the same purpose as prop defaults in my opinion. In UApp, we're not allowed to pass variant for a component type.

variants is a shared prop that practically every component has, just like ui, while other props are not.

Following this argument, one could say that we should even have a size prop that behaves the same as ui and variants, since it's shared amongst many components, but 🤷

@jd-solanki
Copy link
Copy Markdown
Contributor

jd-solanki commented Apr 23, 2026

Here are my thoughts:

  1. Adding variants as prop to UTheme is not appropriate. As we have ui prop, I suggest we introduce props prop:
<UTheme
  :ui="{}"
  :props="{
	tooltip: {
		delayDuration: 150
	}
  }"
/>

Why?

props makes it clear that it accept props for components similar to ui prop


  1. Should UTheme have per-component props (:button, :tooltip) instead of a single nested variants object?

Instead of per component prop, having single props prop allows you easily manage reactivity like watching for a single prop is easier than 50+ values we accept as prop.

  1. Should UTheme only handle contextual/scoped overrides, and global app-wide defaults (Override default props from AppConfig Override default props from AppConfig #2662) live on UApp instead?

Supporting global app-wide props is better idea and less confusing than selecting props like variant only. It also becomes AI to understand that props component will accept any prop and not just few selected which it has to go through docs.


  • I also have thought that in future v5, should we rename this to UTheme -> UConfig? This is because it configures the UI library with theming and component props.

@sandros94
Copy link
Copy Markdown
Member

sandros94 commented Apr 24, 2026

@benjamincanac @sandros94

I don't see why not both - the problem UTheme solved was that the global theme configuration was not enough - we needed theming scoped to subset of the component tree.

@Bobakanoosh I'm mostly worried on a conceptual level atm, I would prefer avoiding transforming UTheme and especially UApp into ticking complexity bombs. But I'm only talking out loud, not forcing any perspective.

In fact, I really like @jd-solanki idea of having a :props, making UTheme only have that and :ui.

<UTheme
  :ui="{}"
  :props="{
	tooltip: {
		delayDuration: 150
	}
  }"
/>

At which point we do not even need color, variant, size dedicated-props, since they now becomes application logic (and not library) without forcing anybody to a single approach.

This also leaves UApp untouched, allowing UConfig renaming for v5 (I also like that naming better tbh, @jd-solanki )

Which means I now more lean to @benjamincanac option 1 ahahahah; it removes the "where is this controlled from?" problem. Since UApp most probably only lives in app.vue, but you might have different UThemes in multiple layouts.

In contrast, with option 2 the DX would force having a combination of multiple UApps and UThemes depending on what you want to do and override where. Which is already confusing to think about right now...

@Bobakanoosh
Copy link
Copy Markdown
Contributor Author

Yeah agreed props is better. I don't have time on my hands to work on this PR at the moment so feel free to take it over

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

Labels

v4 #4488

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UTheme Support for props as well

5 participants