Building custom components in Vue.js/NuxtJS can be a breeze when using a default design that can be easily customized through a JSON configuration

Currently, I am in the process of developing a NuxtJS website where the pages and components can either have a generic design by default or be customizable based on client specifications provided in the URL.

The URL structure is as follows:

http://localhost:3000/registration
- Generic page

http://localhost:3000/client-name/registration
- Client-specific page

To achieve this functionality, I have created a JSON configuration file for each client, such as client-name.json, which follows a specific structure outlined below:

{
  "some_configuration_property": {},
  "another_configuration_property": {},
  "design": {
    "logoUrl": "/assets/client-name/logo.png",
    "backgroundColor": "#000000",
    "primaryColor": "#ffffff",
    "secondaryColor": "#ffff00"
  },
}

I have successfully implemented the routing system to read the client's configuration based on the current route within the Vue file setup method using @nuxt/composition-api. However, I am currently facing an issue on how to pass these "design variables" into the <style> tag of my Vue file, which utilizes SCSS.

  • Initially, I considered using CSS variables to create default values that could be overridden within styles. While this approach worked for individual components, I quickly realized that creating classes for each client would not be ideal due to maintainability concerns.

For example:

// Customizable component
.my-button {
   color: (--button-color, teal);
}

// Styling from a parent component/view
v::deep {
  div {
    &.my-button {
      --button-color: purple;
    }
  }
}
  • Although the /deep/ selector or ::v-deep pseudo selector could be used, it may lead to messy code and decreased maintainability when styling components from parents.

  • Another potential solution involves passing a variable, such as classArray, within the setup method to dynamically bind CSS classes to DOM elements. Yet, creating a CSS class for each client with associated styles could prove cumbersome.

As seen here:

<template>
  <my-button :class="classArray"></my-button>
</template>

<script lang="ts">
import { defineComponent } from '@nuxtjs/composition-api'

export default defineComponent({
  name: 'MyPage',
  setup() {
    const clientName = 'someClientName';
    const classArray = [clientName]
    return { classArray };
  },
})
</script>

<style lang="scss" scoped>
.someClientName {
  // custom styles
}
</style>

What approach would you recommend in handling this situation?

Thank you for your assistance!

Answer №1

To dynamically load custom theme configuration, CSS variables (properties) must be utilized. These variables can be encapsulated within SCSS functions and incorporate default theme fallbacks:

// theme.scss
$primaryColor: #abc;
// $buttonColor: $primaryColor

@function primaryColor() {
  @return #{var(--primary-color, $primaryColor)}
}

@function buttonColor() {
  @return #{var(--button-color, primaryColor())}
}

Subsequently, primaryColor(), etc should replace direct usage of $primaryColor, etc as in conventional SCSS themes:

// Within the customizable component
.my-button {
   color: buttonColor();
}

The custom theme can then be applied on page load either globally across the entire document or selectively to specific components within the hierarchy that necessitate customization:

const config = await loadClientConfig();
document.documentElement.style.setProperty(--primary-color, config.design.primaryColor)

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

Ways to enable automatic scrolling of a page as the content expands (Utilizing collapsible elements)

For a recent project I've been working on, I decided to include 4 collapsible text boxes. However, I encountered an issue where opening content1 would expand and push down content2-4, requiring the user to manually scroll to view the remaining collaps ...

Exploring the world of Vue.js with the latest vue-cli 3.0 and integrating Google Web

I'm completely confused about incorporating Google Fonts into my project. Despite installing the google-fonts-webpack-plugin and attempting to configure it correctly, the html is not being injected. Perhaps I am approaching this problem from the wron ...

Resolve Bootstrap 4 responsive table header alignment glitch

Utilizing the d-none and d-md-block classes on a responsive table to hide certain columns at smaller screen sizes has been successful overall. However, there is one issue - the hidden columns seem to be slightly misaligned with the rest of the table. Despi ...

Tips and tricks for retaining the collapsed state upon reloading Bootstrap 5

Just diving into the world of bootstrap and javascript. How do I save the collapsed state to make sure it stays even after refreshing the page? <p> <button class="btn btn-primary" type="button" data-bs-toggle="collapse&q ...

The Street View feature on Google Maps API is now showcasing a cool,

I have been attempting to showcase the interior of various businesses using the Google Maps API street view feature. Initially, I was able to retrieve the place_id and then use it to access any available street view panoramas. However, this functionality s ...

Invoke the wrapper function within the jQuery AJAX `complete` callback

I am currently trying to accomplish a task, but I keep receiving an error message stating that I cannot bind to undefined. I suspect this is happening because I am working within an anonymous function. My goal is to be able to access the method (getAndSayH ...

Transferring binary fragments to Node.js for assembly into a complete file. Creating a file

Hey there, I'm in a bit of a bind. I'm trying to send file chunks using multiple XMLHttpRequest requests and then receive these parts in Node.js to reconstruct the original file from the binary data. The issue I'm facing is that the final f ...

What is the best way to refresh an Angular scope variable with data obtained from the Google Maps Places API?

I am looking to implement a feature where users can search for locations using the Google Places API. When they click on a specific location, I want to update a parameter value in the scope. Here is a visual representation: The Google integration works s ...

I am facing an issue where the PHP header redirection stops working after implementing event.preventDefault() on form submission

After successfully implementing jQuery in my signup page to handle and check the form fields, I encountered an issue where the header("location: ../****.php") no longer redirected me to another page upon clicking submit. Instead, it loaded the new page on ...

Discover the correct way to locate the "_id" field, not the "id" field, within an array when using Javascript and the MEAN stack

I am working on an Angular application that connects to MongoDB. I have a data array named books, which stores information retrieved from the database. The structure of each entry in the array is as follows: {_id: "5b768f4519d48c34e466411f", name: "test", ...

What is the best way to bring a "subdependency" into ES6?

I am dealing with a situation where I have a package called react-router, which relies on another package called path-to-regexp. The challenge is that react-router does not provide its own import of path-to-regexp. So, I am wondering how I can import the e ...

Filling in a text field with the text content (rather than the value) from a dropdown menu

Presently, I have the select box with the id "title" populating a text field with the id "costcenter". The current code works perfectly fine when using the VALUE of the select box to trigger the population of the cost center field. However, my requirement ...

How can I utilize columns from a junction table in the "where" clause in sequelize?

Looking to execute a Sequelize query on multiple related models: SELECT Cou.country_id, cou.country_name, Sta.state_id, Sta.state_name, Dis.district_id, Dis.district_name, Cit.city_id, Cit.city_name, Loc.location_id, Loc.location_name, Sub_Loc.sub_locatio ...

The data retrieved from the PHP script is not accessible within the main Vue instance

I am currently working on a Vue.js component for a modal window. Once the user fills out all the necessary data in the fields, I need to achieve the following: Send the data to the server. Apply a timeout to show the user that the data is being sent (by ...

From plain to vibrant: Using CSS gradients for background design

I have customized a button by adding a gradient to it. Below is the code snippet: .mybutton { background: #258dc8; /* Old browsers */ background: -moz-linear-gradient(top, #258dc8 0%, #258dc8 100%); /* FF3.6+ */ background: -webkit-gradient( ...

How can we trigger a mutation in Vue.js using the created or mounted hook?

I've encountered an issue in my Vue.js application with the store.js file where I'm setting up a Vuex store. Here's how it looks: import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export const store = new Vue ...

"Angular ng-repeat: Restrict all items from being interacted with, except

I have a collection of items, each wrapped in a div element. I am trying to display only the first item as enabled while disabling the rest. AngularJs angular.module('example', []) .controller('myCtrl', function Ctrl($scope) { $sc ...

Guide to deserializing JSON with a dynamically changing root key

I am having difficulties working with this JSON data. {"1234345": [{ "queue": "XXX", "name": "XXXXX", "entries": [{ "points": 54, "isInactive": false, }], "tier": "ASDF" }]} However, the JSON data can also have a different structure: ...

Ways to ensure the CSS style remains active even after clicking the button

Is there a way to make the effect appear only when the button is clicked, then disappear after it's released? I've seen examples using addEventListener and directly changing the style with btn.style.color="" (reference) or using btnEl.c ...

Utilize Nifi's Execute Script Processor with Groovy to perform automated data transformation

I am seeking a solution to dynamically modify the date format of my JSON file before sending it. import groovy.json.* def ff = session.get() if(!ff) return ff = session.write(ff, {rawIn, rawOut-> //parse flowfile content to maps & arrays d ...