Change the Vue3 PrimeVue theme or CSS file with a simple click or upon page load

One way to incorporate themes is by importing them in the main.js file at the root of the app:

import 'primevue/resources/themes/arya-orange/theme.css';

However, I am exploring ways to dynamically switch CSS files based on the user's system theme and selection. Therefore, I moved this logic into my main App.vue:

export default {
  name: "App",
  components: {
    HelloWorld,
    toDo,
  },
  mounted() {

    //window.matchMedia('(prefers-color-scheme: dark)').matches ? do dark : do light
  },
};

<style>
@media (prefers-color-scheme: dark) {
  @import url("primevue/resources/themes/bootstrap4-dark-blue/theme.css");
}
@media (prefers-color-scheme: light) {
  @import url("primevue/resources/themes/bootstrap4-light-blue/theme.css");
}
</style>

I cannot import anything inside mounted, and importing inside media queries within style tags is not considered correct usage.

After researching, I could not find any alternative solutions or guidance to resolve this issue. The existing solutions mainly focus on scoping components and using classes.

One approach I could consider is consolidating all rules for one theme under:

@media (prefers-color-scheme: dark) {

and another set for the light theme. However, this does not address how to switch themes based on user selection.

EDIT:

I managed to make it work upon loading:

(async () => {
  if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
    await import('primevue/resources/themes/bootstrap4-dark-blue/theme.css');
  } else {
    await import('primevue/resources/themes/bootstrap4-light-blue/theme.css');
  }
})();

Additionally, on user click, the initial import can be overridden with:

  methods: {
    theme() {
      (async () => {
          await import("primevue/resources/themes/bootstrap4-light-blue/theme.css");
      })();
    },
  },

HOWEVER, when attempting to toggle back to the original theme upon click, nothing happens. This might be due to the dark theme being loaded initially if the system was set to dark. As a result, toggling back to the dark theme upon click does not take effect because it was already loaded initially.

Any suggestions would be greatly appreciated.

Answer №1

To achieve the desired outcome, one method is to follow the approach adopted on the PrimeVue website. Essentially, the css theme is incorporated by including a link in the index.html file:

<!DOCTYPE html>
<html lang="en">
    <head>
...
<link id="theme-link" rel="stylesheet" href="<%= BASE_URL %>themes/saga-blue/theme.css">
    </head>
    <body>
...
    </body>
</html>

For reference and demonstration, please view this specific example.

In order to dynamically switch themes, you can implement a function similar to this one:

changeTheme(event) {
    let themeElement = document.getElementById('theme-link');
    themeElement.setAttribute('href', themeElement.getAttribute('href').replace(this.theme, event.theme));
    this.theme = event.theme;
    this.activeMenuIndex = null;
    EventBus.emit('change-theme', event);
    this.$appState.darkTheme = event.dark;
    if (event.theme.startsWith('md')) {
        this.$primevue.config.ripple = true;
    }
    localStorage.setItem('theme', this.theme);
}

This methodology mirrors the practices outlined in the PrimeVue documentation. For further insight, visit this associated resource.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to convert Firebase snapshot JSON data to text format instead of an object in Vue.js

After successfully pulling the data, it shows up as an object in my view: { "-MH8EpUbn1Eu3LdT0Tj0": { "code": "https://www.apesyntax.com", "content": "This is the tut content", "date": "2020- ...

Ensuring that two operators are not consecutively placed in a Javascript calculator-validation guide

After creating a basic calculator using HTML, CSS, and JavaScript, I encountered an issue. When validating user input, the calculator currently accepts multiple operators in a row. To address this, I attempted to prevent consecutive operators by checking ...

Looking for a way to automatically update a map within a Vue component

My component successfully: Receives a string from a sibling input component via the global Bus method in created() => works Manipulates the string into lat/lng coordinates via geoDecoding() => works Resolves promise result coordinates, sets data, a ...

initiate scanning for HTTP GET calls

My current project involves using electron to create an application that serves multiple image files through a webserver using express. Another app built for Android is responsible for retrieving and posting files to this server. While I have successfully ...

What is the optimal order for executing JavaScript, jQuery, CSS, and other controls to render an HTML page efficiently?

What are some recommended strategies for optimizing webpage loading speed? What key factors should be taken into consideration? ...

Typescript raises a error notification regarding the absence of a semicolon when importing a JSON module

Attempting to import a local JSON object into my Vuex store using const tree = import('@/articles/tree.json');. The setting "resolveJsonModule": true, has been enabled in my tsconfig.json and it loads successfully, however NPM is flooding the out ...

Enhanced Search and Replace Techniques in HTML using jQuery and JavaScript

Although I have some experience with jQuery and Javascript, I am by no means an expert. I have been struggling to find a way to achieve my goal using minimal resources. Maybe you can assist me: This is what I am trying to accomplish: I would like to use ...

The function returning the map finished before the foreach loop

I recently created a program that computes totals by multiplying a given rate with some hours. However, I've encountered an issue with the getTasks() function always returning an empty map. Even though the fields entered in the map are not empty, the ...

Switch classes according to scrolling levels

My webpage consists of multiple sections, each occupying the full height and width of the screen and containing an image. As visitors scroll through the page, the image in the current section comes into view while the image in the previous section disappe ...

Using JavaScript, transform a client's date/time string into a JSON-compatible date/time string

I need to find a way to convert a client's date/time string on a form into a JSON date/time string using JavaScript with moment.js for a Django REST API backend service. Here is the initial attempt: document.getElementById("dt_tm").value = moment(do ...

Firefox does not allow contenteditable elements to be edited if they are nested inside a parent element that is draggable

Here is a basic HTML example: <div draggable=true> <div contenteditable=true>can't edit me</div> </div> When testing in Chrome, I noticed that I was able to edit the contents of the contenteditable div, however, this functi ...

Skipping the configuration file during the process of converting Node.js files to an executable using pkg

I am currently working on a node.js application and in order to prevent users from reading the code, I am attempting to convert my JavaScript files to executable files. I have been using the pkg module for this task, but I have encountered an issue. The p ...

Utilizing various Firestore requests at varying intervals using the useEffect hook in React

useEffect(async() => { await getWord(); const interval = setInterval(() =>{ time2 = time2 - 1; if (time2 == 0) { clearInterval(interval); let dataURL = canvasRef.current.toDataURL(); const db = firebase.firestore(); ...

Using a for loop in JavaScript to dynamically display TextBoxFor(model=> model[i].prop) in an MVC application

I need some help getting this code to function correctly: $('#ddl').change(function () { $('#cont').html(''); var count = getCount($('#ddl').val()) for (var i = 0; i < count ; ...

fresh map from Google: Coordinates LatLng may not be a number, but my hunch tells me it is

Seeking Assistance with this Issue - For example, the initial location data appears as: "Object Lat: -36.768498 Lng: 174.75895" However, an error is indicating that the latitude is not recognized as a number. Rather than making adjustments without clea ...

Implementing slideDown() functionality to bootstrap 4 card-body with jQuery: A step-by-step guide

Here is the unique HTML code I created for the card section: <div class="row"> <% products.forEach(function(product){ %> <div class="col-lg-3 col-md-4"> <div class="card mb-4 shadow "> &l ...

Regular expressions are compatible with JavaScript, but unfortunately, they are not supported

After successfully implementing this regex in my JavaScript for webpage validation, I attempted to incorporate it into my PHP script as a backup. However, every string I passed through the regex failed, even correct names. In an effort to resolve the issu ...

Receive information from a form and store it in an array

Struggling to figure out how to convert this into an array. I'm having trouble grasping the concept of taking input from a form and storing it in an array. In my project instructions, it clearly states: Do NOT save the input in variables and then tra ...

simulate the act of clicking on a download link by utilizing a secondary click

adown is a link that allows users to download a file from my webpage. It functions properly on the page. However, btndown is a button designed to simulate clicking on the adown link, but unfortunately, it does not work as expected. When the btndown button ...

Attempting to alter the background image through the action of clicking on an image using jQuery, HTML, and CSS

I have created custom weather icons like a sun, cloud, and rainy cloud using Photoshop. My goal is to allow users to click on these icons and change the background image of the website's body. However, despite my efforts, clicking on the images does n ...