primevue icon indicating copy to clipboard operation
primevue copied to clipboard

Default theme CSS wins over custom preset in 4.3.4 and 4.3.5

Open proprofondo opened this issue 6 months ago • 10 comments

Describe the bug

After upgrade to 4.3.5 styles from custom preset are not applied. They are present in browser, but default theme CSS wins over the customized one. In the given example the button gets custom color in 4.3.3 but does not get it in 4.3.4 and 4.3.5

Pull Request Link

No response

Reason for not contributing a PR

  • [ ] Lack of time
  • [x] Unsure how to implement the fix/feature
  • [ ] Difficulty understanding the codebase
  • [ ] Other

Other Reason

No response

Reproducer

https://stackblitz.com/edit/primevue-4-vite-issue-template-scdqp96w?file=package.json

Environment

Chrome on Windows 11

Vue version

3

PrimeVue version

4.3.5

Node version

20.19.1

Browser(s)

No response

Steps to reproduce the behavior

  1. Create custom theme preset using definePreset
  2. Add theme-dependent style for the component, e.g. components->button->colorScheme->dark->warn->color
  3. The button gets default value of the var(--p-button-warn-color)

Reproducible for different components and styles in the preset, not only buttons.

Expected behavior

The button should get re-defined color from custom preset. The CSS var with the desired value is present but later overwritten and not being applied. Downgrade to 4.3.3 fixes the problem.

Image

proprofondo avatar Jun 06 '25 03:06 proprofondo

I can't tell you what changed between 4.3.3 and 4.3.5, but what i can tell you is that your example code misses the "root" level.

You wrote:

(...)
dark: {
  warn: {
    color: 'green',
  },
},
(...)

But it should be

(...)
dark: {
  root: {
    warn: {
      color: 'green',
    },
  },
},
(...)

With this change in place i see the color as expected: https://stackblitz.com/edit/primevue-4-vite-issue-template-tgzju65j?file=src%2FCustomPreset.js,index.html

Your code:

Image

After my changes:

Image

That being said, somebody else on the PrimeTek community Discord server also wrote they were hit by this change, @mertsincan is it possible that something was changed in the primeuix version between 4.3.3 and 4.3.5 that causes this change in behavior?

MelkorCC avatar Jun 06 '25 18:06 MelkorCC

I edited the example @proprofondo provided to primevue 4.3.3 and sure enough, there root isn't required. https://stackblitz.com/edit/primevue-4-vite-issue-template-wddjuals?file=package.json (primevue 4.3.3) starting with 4.3.4 it seems to be required https://stackblitz.com/edit/primevue-4-vite-issue-template-qphpxrw6?file=package.json (primevue 4.3.4). Only change between these two is the primevue version. @mertsincan could this be an regression / undocumented breaking change in primeuix?

MelkorCC avatar Jun 06 '25 18:06 MelkorCC

Just as information for others...

Be aware if you’re still using the old package to import themes. PrimeVue migrated to @primeuix/themes some time ago. I previously used the old @primevue/themes package in another project and encountered the same button styling issue you described. As MelkorCC mentioned above, the token structure has also changed.

You can find the design tokens for each design at the bottom of this page.

  • https://primevue.org/button/

Here’s the link to the Aura theme design tokens (export const colorScheme):

  • https://github.com/primefaces/primeuix/blob/main/packages/themes/src/presets/aura/button/index.ts

borsTiHD avatar Jun 07 '25 07:06 borsTiHD

I'm also encountering CSS-related issues with PrimeVue 4.3.4 and 4.3.5, which are resolved by downgrading to 4.3.3.

In my specific case, while my custom PrimeVue theme (created using definePreset based on the Lara theme from @primeuix/themes) appears to apply its own semantic colors and component-specific overrides correctly, I've found that Tailwind CSS utility classes used on or around PrimeVue components are no longer rendering as expected.

For example, if I apply a Tailwind class like border-black to an element, it shows up correctly in the browser's devtools, but the border doesn't actually render visually.

Downgrading PrimeVue to 4.3.3 resolves this problem, and my Tailwind classes render correctly again alongside PrimeVue.

My setup is a Nuxt 3 project using @primevue/nuxt-module and Tailwind CSS. Here's the relevant part of my nuxt.config.js showing how the PrimeVue preset is defined and used:

import { definePreset } from '@primeuix/themes';
import Lara from '@primeuix/themes/lara';

const mainColor = 'somecolor'; // My actual color value
const CustomLara = definePreset(Lara, {
  // ... my semantic and component customizations
  semantic: {
    primary: {
      500: mainColor,
      // ... other shades
    }
  },
  components: {
    progressspinner: { /* ... custom spinner styles ... */ }
  }
});

// ...
export default defineNuxtConfig({
  // ...
  primevue: {
    options: {
      theme: {
        preset: CustomLara,
        options: {
          prefix: 'pv',
          // ... other options
        }
      },
    },
  },
  // ...
});

ct255 avatar Jun 07 '25 21:06 ct255

Be aware if you’re still using the old package to import themes. PrimeVue migrated to @primeuix/themes some time ago. I previously used the old @primevue/themes package in another project and encountered the same button styling issue you described.

@borsTiHD Actually @primevue/themes just reexports primeuix stuff. So while you are correct, people should migrate, this is probably not the problem here (random example from 4.3.3: https://github.com/primefaces/primevue/blob/4.3.3/packages/themes/src/presets/aura/button/index.js )

@ct255 i think this is something that should be tracked in a different issue and you might also want to provide a minimal reproducer on stackblitz

MelkorCC avatar Jun 08 '25 19:06 MelkorCC

I think this is the same as the unresolved issue in https://github.com/primefaces/primevue/issues/7258 .

micvm avatar Jun 11 '25 12:06 micvm

@borsTiHD I can confirm that the issue is not affected by in which way you load theme library. I used @primevue/themes and upgrade to @primeuix/themes was actually my first guess. But it didn't help. While changing version of the primevue itself does the change.

@MelkorCC thanks for the hint with root. It fixes the issue. But I have many components re-styled in old way and would like to avoid refactoring. So I leave the ticket open for now, till fixed or documented that root is mandatory from now on.

Thanks

proprofondo avatar Jun 12 '25 00:06 proprofondo

@MelkorCC / @proprofondo Yes, I also noticed this when I took a closer look at the export of the package. My bad. I edited my post as “general info”. For my problem, I migrated to the correct package and also adjusted the object structure.

borsTiHD avatar Jun 12 '25 10:06 borsTiHD

Be aware if you’re still using the old package to import themes. PrimeVue migrated to @primeuix/themes some time ago. I previously used the old @primevue/themes package in another project and encountered the same button styling issue you described.

@borsTiHD Actually @primevue/themes just reexports primeuix stuff. So while you are correct, people should migrate, this is probably not the problem here (random example from 4.3.3: https://github.com/primefaces/primevue/blob/4.3.3/packages/themes/src/presets/aura/button/index.js )

@ct255 i think this is something that should be tracked in a different issue and you might also want to provide a minimal reproducer on stackblitz

so sorry, seem like that is about my config and the prefix, I found out that the PrimeUI is hard coded the --p so the prefix I set not work, so I remove it and it good to go, but still have no clue why downgrade work

ct255 avatar Jun 14 '25 01:06 ct255

Hello! Could you help me with such question, please? In my library I have primevue.ts

import type { App } from "vue";

import PrimeVue from "primevue/config";
import Button from "primevue/button";
import Toast from "primevue/toast";
import ToastService from "primevue/toastservice";
import Ripple from "primevue/ripple";
import Lara from "@primeuix/themes/lara";
import { definePreset } from "@primeuix/themes";
import "../styles/fabrix-colors.css";
import { palette } from "@primeuix/themes";

export const applyThemeColors = () => {
const computedStyle = getComputedStyle(document.documentElement);
const primaryColorValue = computedStyle.getPropertyValue("--primary-color");
const primaryColor = palette(primaryColorValue);

return {
primary: primaryColor,
secondary: {
50: "{gray.50}",
100: "{gray.100}",
200: "{gray.200}",
300: "{gray.300}",
400: "{gray.400}",
500: "{gray.500}",
600: "{gray.600}",
700: "{gray.700}",
800: "{gray.800}",
900: "{gray.900}",
950: "{gray.950}",
},
};
};

export const MyPreset = definePreset(Lara, {
semantic: applyThemeColors(),
//Your customizations, see the following sections for examples
});

export const PrimeVuePlugin = {
install: (app: App) => {
applyThemeColors();
app.use(PrimeVue, {
ripple: false,
theme: {
preset: MyPreset,
options: {
prefix: "p",
darkModeSelector: "system",
cssLayer: {
name: "primevue",
order: "prime, primevue, fabrix",
},
},
},
});
app.use(ToastService);
app.component("Button", Button);
app.component("Toast", Toast);
app.directive("ripple", Ripple);
},
};

I use this library in another project like this: main.js

import "primeicons/primeicons.css";
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
// Fabrix styling:
import { UiKitPlugin, MyPreset } from "@fabrix/ui-kit";
import { applyThemeColors } from "@fabrix/ui-kit";
import "@fabrix/ui-kit/ui-kit.css";
import PrimeVue from "primevue/config";

App.created = function () {
if (this.created) this.created();
this.$auth.init();
};
const app = createApp(App);
console.log("First version of preset is", MyPreset);

const themeColors = applyThemeColors();
console.log("Theme colors", themeColors);

const themeConfig = {
...MyPreset,
semantic: {
...MyPreset.semantic,
primary: themeColors.primary,
secondary: themeColors.secondary,
},
};

console.log("Updated preset is", themeConfig);

app.use(PrimeVue, {
theme: { preset: themeConfig },
});

app.use(UiKitPlugin, import.meta.env);
app.mount("#app");
export default app;


The colors from the library are not being applied in the project that uses it.

Though the colors in the themeConfig object are exactly as expected and correct, but they are not being applied despite using the following configuration:

app.use(PrimeVue, {
  theme: { preset: themeConfig },
});

The CSS-variable is defined in my library like this:

fabrix-colors.css

:root {
--primary-color: #1f36c7;

} How should I act to fix this?

I tried to use not only this method, but, for example, another one method: primevue.ts

import type { App } from "vue";
 
import PrimeVue from "primevue/config";
import Button from "primevue/button";
import Toast from "primevue/toast";
import ToastService from "primevue/toastservice";
import Ripple from "primevue/ripple";
import Lara from "@primeuix/themes/lara";
import { definePreset } from "@primeuix/themes";
import "../styles/fabrix-colors.css";
import { palette } from "@primeuix/themes";
 
const computedStyle = getComputedStyle(document.documentElement);
const primaryColorValue = computedStyle.getPropertyValue("--primary-color");
const primaryColor = palette(primaryColorValue);
 
export const MyPreset = definePreset(Lara, {
  semantic: {
    primary: primaryColor,
    secondary: {
      50: "{gray.50}",
      100: "{gray.100}",
      200: "{gray.200}",
      300: "{gray.300}",
      400: "{gray.400}",
      500: "{gray.500}",
      600: "{gray.600}",
      700: "{gray.700}",
      800: "{gray.800}",
      900: "{gray.900}",
      950: "{gray.950}",
    },
  },
  //Your customizations, see the following sections for examples
});
 
export const PrimeVuePlugin = {
  install: (app: App) => {
    app.use(PrimeVue, {
      ripple: false,
      theme: {
        preset: MyPreset,
        options: {
          prefix: "p",
          darkModeSelector: "system",
          cssLayer: {
            name: "primevue",
            order: "prime, primevue, fabrix",
          },
        },
      },
    });

main.js

import ConfirmationService from "primevue/confirmationservice";
import ToastService from "primevue/toastservice";
import Tooltip from "primevue/tooltip";
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
// Fabrix styling:
import { UiKitPlugin, MyPreset } from "@fabrix/ui-kit";
import "@fabrix/ui-kit/ui-kit.css";
import "primeicons/primeicons.css";
import axios from "axios";
import qs from "qs";
import store from "./store/store";
 
import PrimeVue from "primevue/config";
 
App.created = function () {
  if (this.created) this.created();
  this.$auth.init();
};
const app = createApp(App);
console.log("First version of preset is", MyPreset);
 
/
 
app.use(PrimeVue, {
  theme: { preset: MyPreset },
});
 
axios.defaults.baseURL = import.meta.env.CLIENT__API_BASE_URL;
axios.defaults.withCredentials = true;
axios.defaults.paramsSerializer = (params) =>
  qs.stringify(params, { arrayFormat: "comma" });
 
app.use(router);
app.use(store);
app.use(UiKitPlugin, import.meta.env);
app.use(ToastService);
app.use(ConfirmationService);
app.directive("tooltip", Tooltip);
 
app.mount("#app");
 
export default app;
 

the result is the same.

And when I do like this in my library,

primevue.ts

import type { App } from "vue";
import PrimeVue from "primevue/config";
import Button from "primevue/button";
import Toast from "primevue/toast";
import ToastService from "primevue/toastservice";
import Ripple from "primevue/ripple";
import Lara from "@primeuix/themes/lara";
import { definePreset } from "@primeuix/themes";
import "../styles/fabrix-colors.css";
import { palette } from "@primeuix/themes";
 
// const computedStyle = getComputedStyle(document.documentElement);
 
// const primaryColorValue = computedStyle.getPropertyValue("--primary-color");
const primaryColorValue = "#1f36c7";
const primaryColor = palette(primaryColorValue);
 
export const MyPreset = definePreset(Lara, {
  semantic: {
    primary: primaryColor,
    secondary: {
      50: "{gray.50}",
      100: "{gray.100}",
      200: "{gray.200}",
      300: "{gray.300}",
      400: "{gray.400}",
      500: "{gray.500}",
      600: "{gray.600}",
      700: "{gray.700}",
      800: "{gray.800}",
      900: "{gray.900}",
      950: "{gray.950}",
    },
  },
  //Your customizations, see the following sections for examples
});
 
export { PrimeVue };
 
export const PrimeVuePlugin = {
  install: (app: App) => {
    app.use(PrimeVue, {
      ripple: false,
      theme: {
        preset: MyPreset,
        options: {
          prefix: "p",
          darkModeSelector: "system",
          cssLayer: {
            name: "primevue",
            order: "prime, primevue, fabrix",
          },
        },
      },
    });
    app.use(ToastService);
    app.component("Button", Button);
    app.component("Toast", Toast);
    app.directive("ripple", Ripple);
  },
};

the colors in the project, that uses this library are correct. But I really need to use CSS variables in my library, so this variant is not suitable

Maksk89 avatar Jun 17 '25 14:06 Maksk89

Correct implementation is:

button: {
      colorScheme: {
        light: {
          root: {
            warn: {
              color: 'blue',
            },
          }
        },
        dark: {
          root: {
            warn: {
              color: 'green',
            },
          }
        },
      },
    }

tugcekucukoglu avatar Jun 19 '25 11:06 tugcekucukoglu

@tugcekucukoglu that doesn't explain tho why the behavior changed between 4.3.3 and 4.3.4 and why this change wasn't mentioned in the release notes.

MelkorCC avatar Jun 19 '25 11:06 MelkorCC