DEV Community

Cover image for How to share SASS variables with JavaScript code in VueJS
Matteo Fogli
Matteo Fogli

Posted on • Updated on

How to share SASS variables with JavaScript code in VueJS

Having a single variable declaration that works across different coding languages is a goal every developer strives to reach, no matter the technology or framework they adopt. It brings together convenience (update the value once, see it working everywhere) with consistency and lower runtime error rates.

This post explains how to share variables between Sass and JavaScript in VueJS. It will be useful every time you have layout constraints that need to be shared with front-end logic. The opposite case, where business logic determines styles update, is mostly solved with inline styles on DOM elements and CSS Custom Properties. CSS Custom Properties are well supported, but if you are looking for a solution based on SASS, keep on reading.

Step 1: Export variables from SASS/SCSS

We can use a feature borrowed from CSS Modules to export SASS variables and make them available as imports to JavaScript code. We combine a syntax :export with a webpack loader CSS Loader that provides the exported values to JavaScript imports.

:export is implemented as a pseudo-selector and as such is completely transparent to SASS:

$your-sass-var: #663399;

:export {
  variablename: $your-sass-var;
}
Enter fullscreen mode Exit fullscreen mode

This declares an SCSS variable and exports it under the variablename identifier.

Step 2: Import SASS/SCSS variables in JavaScript

The easiest way to import your exported SASS variables is to import the SASS file itself.

import exportedVars from './path/to/file.scss' 
Enter fullscreen mode Exit fullscreen mode

But with Vue, we rarely author styles as independent SCSS or SASS files. Most of the time you’d author Single File Components, a custom VueJS file format that uses HTML-like syntax to describe a Vue component, usually including a template, a script and a style block.

So how do you import only the style code block from a SFC? It took me a while to find the answer, but the hint is "the same way webpack does". You ask Vue Loader to do it for you.

Vue Loader turns a single file into an export of three (or more) files. In doing so, it rewrites the source filename with a syntax that allows to address a specific block. Like this:

import exportedVars from './path/to/file.vue?vue&type=style&index=0&lang=scss&module=1' 
Enter fullscreen mode Exit fullscreen mode

./path/to/file.vue is your usual reference to the target file. If you are importing from the style block within the same SFC, use ./yourcomponentname.vue. Next is the ?vue query string part. This allows Vue Loader to understand it has already destructured the SFC into parts and should provide the code block based on its type and index. &type=style, &index=0 and &lang=scss allow Vue Loader to fetch the correct block and pass it to the correct preprocessor.

The index parameter allows to address multiple style blocks that might be in an SFC.

Lastly, more recent versions of vue-loader strictly enforce exports for CSS modules only. Appending &module=1 provides a default export when self importing our styles.

Step 3: Use your imported variables

Sass variables are accessible as properties of the identifier used for import, e.g. identifier.variablename:

Here is a complete (and simplicistic) full example:

<template>
  <div>
    <p>Andy Kaufman {{ lyrics }}</p>
  </div>
</template>
<script>
import styles from './ManOnTheMoon.vue?vue&type=style&index=0&lang=scss&module=1'

export default {
  name: 'ManOnTheMoon',
  data() {
    return {
      lyrics: styles.lyrics,
    }
  },
}
</script>
<style lang="scss">
$lyrics: ' in the wrestling match';

:export {
  lyrics: unquote($lyrics);
}
</style>
Enter fullscreen mode Exit fullscreen mode

Which will display the phrase: "Andy Kaufman in the wrestling match"1.

Note: that all variables are exported as strings. Use type casting and conversion if you need to coerce a value to number or boolean.

Wrapping up

This article focuses on VueJS, but this approach is valid with any framework or build pipeline that relies on webpack with css-loader.

CSS Custom Properties (AKA CSS Vars) provide an even smoother implementation: you can read and update custom properties via element.style.getPropertyValue() and element.style.setProperty() respectively, and I encourage you to make the switch and adopt CSS Custom Properties in place of SASS vars (even within SASS!). Yet, this solution can be useful if you already have a fully developed project built on SASS variables where refactoring to CSS Custom Properties is not an option.


  1. If you caught the reference in the example, I suspect that you’ll be singing "Yeah, yeah, yeah, yeah" in your head by now. At modo we can't miss a chance to drop an R.E.M. reference if we can 😬
  2. Cover Photo by Lucas Benjamin on Unsplash

Latest comments (2)

Collapse
 
chrisross5 profile image
Chris

I get "SassError: This file is already being loaded." because I want to use variables that I already imported globally in config's additionalData... so how do I find a reference? Thx

Collapse
 
pecus profile image
Matteo Fogli

I didn't catch this, sorry for the late reply. Sass files added via the additionalData config option will not be made available to your JavaScript context even if you :exportyour sass variables. In order to inject variables in the JavaScript context, you need to explicitly import the sass file that declares and exports them.

// _variables.scss
// this file is added via the additionalData loader option in vue.config.js
$lyrics: 'if you believe';

:export {
  lyrics: unquote($lyrics);
}
Enter fullscreen mode Exit fullscreen mode
// Component.vue
<script>
import styles from './_variables.scss'
export default {
    data() {
        return {
            lyrics: styles.lyrics,
        }
    },
}
</script>
Enter fullscreen mode Exit fullscreen mode

You may need to set css.requireModuleExtension to false in your vue.config.js.