Using @use & @forward in SASS

I have been working with CSS over the years and love it. I have tried various libraries, toolsets like Bourbon (yes, I am that old), and pre-processors like SASS & Less.

Talking about the CSS pre-processors, lately, I was reading about how node-sass will be deprecated soon, and hence, I checked out the dart-sass documentation.

While reading the documentation, I came across an exciting way of importing the SASS files instead of the traditional way of importing the stylesheets using @import statements.

Yes, just like me, you must have thought the same, that what would be better than using @import statements to import the Stylesheets? Well, dart-sass has to offer two new ways of importing them, namely @use and @forward.


Important: Make sure that you have sass installed, and NOT node-sass

Before we try out the new ways to handle the imports using SCSS, we will first define the Files & the Folder structure.

/project
|-- /vars
|---- _colors.scss
|---- _fonts.scss
|-- app.scss

Let’s try out @use

As you know, we can import the files in SCSS using the @import statement. @use pretty much does the same thing, EXCEPT, that it namespaces your variables, thus, preventing the name collisions.

Starting with some simple code here, we will create a file to hold some variables, and then we will require this in our App file.

// _colors.scss
$h1-color: #f00;
$component-color: #0f0;

And then, we will use @import first, in app.scss to test if everything’s in place.

// app.scss
@import 'vars/colors';

h1 {
  color: $h1-color;
}

The above should work as expected. Now, without any further ado, we will go ahead and modify the @import statement to @use.

// app.scss
@use 'vars/colors';

h1 {
  color: $h1-color;
}

@use helps you namespace your SCSS files

Now that we are using @use it to import the stylesheet will result in an error. Reason? Remember, in the beginning; I mentioned that @use helps us namespace our variable names, thus preventing collisions if any. Hence, we need to modify the above code like:

// app.scss
@use 'vars/colors';

h1 {
  color: colors.$h1-color;
}

Viola, the SCSS is now compiled. All we did was, prefixed the @h1-color variable using colors that are nothing but the file name.


@use(ing) Alias

Now, what if we have a file name of _colors_for_theme_blue.scss (not pretty at all but assuming some worst-case scenario), and then writing it like colors_for_theme_blue.$h1-color will be super annoying.

To cut short the filename, you can use the keyword as that will help you create an alias for the _colors.scss file. E.g.:

// app.scss
@use 'vars/colors' as c;

h1 {
  color: c.$h1-color; //note that now we are using only c here
}

as helps you define an alias for the file name you are importing using the @use keyword.

Alternatively, you could also use an * as an alias which will result in behavior similar to the one which @import provides. For, e.g.:

// app.scss
@use 'vars/colors' as *;

h1 {
  color: $h1-color; 
  /* note, you need not have to specify colors prefix before you use $h1-color variable. */
}

I would not recommend you doing the above since it misses the point in having name-spaced variables.


Scope using @use vs. @import

There is another benefit of using @use instead of the @import is the scope. When we use @import statement to import certain files, then this file has access to the declared variables before importing the component file. For, e.g.: (we will introduce a new folder here, say components, and create a sample component file like _my_component.scss)

/project
|-- /components
|---- _my_component.scss
|-- /vars
|---- _colors.scss
|---- _fonts.scss
|-- app.scss

Here, we will try to import _my_component.scss using the @import statement and then using the @use and see the difference.

// app.scss
// using @import
@import 'vars/colors';
@import 'components/_my_component';

h1 {
  color: $h1-color;
}

And here we have some code in the _my_component.scss file

// _my_component.scss
.my-component {
  color: $component-color;
}

In the above example, the code will be compiled as expected, where even the _my_component.scss has access to the variables declared in the app.scss file, create issues as the codebase grows.

The above results in the following compiled CSS

// compiled output
.my-component {
  color: #0f0;
}

h1 {
  color: #aaa;
}

If you notice, the .my-component can access the colors defined in a separate file imported before importing the component file.

If we make use of @use instead of the @import, here’s what will happen.

// app.scss
// using @use
@use 'vars/colors' as c;
@use 'components/_my_component';

h1 {
  color: c.$h1-color;
}

Tweaking the component file a bit:

// _my_component.scss
.my-component {
  color: c.$component-color;
}

The above will result in an error:

Error: There is no module with the namespace “c”.

Say if we remove the namespace, which is c, then the error which we will get is

Error: Undefined variable.

Hence, using @use helps you control the scope of your variables instead of @import which makes the variables globally accessible to the files which are imported post the variable file. Still, if you wish to use the same variable file in the _my_components.scss then you need to require the variables in the components file as well.

// _my_component.scss
@use '../vars/colors' as c; //note the filepath here,have added ../

.my-component {
  color: c.$component-color;
}

.my-component {
  color: c.$component-color;
}

Using @forward

You must be having multiple helper files, say for variables, mixins, fonts, extends, etc. Having to require them in every single file (since using @use, it will not make these files globally available) required in components and other SASS files will be tedious.

Hence, we could use @forward which acts like a pipe. It takes many files and makes the contents of those files available where this file is required. Let us take an example:

/project
|-- /components
|---- _my_component.scss
|-- /vars
|---- _colors.scss
|---- _fonts.scss
|---- helpers.scss 

/* we will add this file here, which will contain forwards of _colors.scss & _fonts.scss */
|-- app.scss

And now we will add the @forward to the helpers.scss file.

// helpers.scss
@forward 'colors';
@forward 'fonts';

Now instead of requiring every helper file in app.scss you would instead import the helpers.scss which will make the other files like _colors.scss & _fonts.scss available.

// app.scss
@use "vars/helpers";
@use "components/my_component";

h1 {
  color: helpers.$h1-color; 
  /* note that you need to modify the namespace, or use * and you could simply use $h1-color */
}

and subsequently, we can now modify the _my_component.scss file as well.

// _my_component.scss
@use "../vars/helpers";

.my-component {
  color: helpers.$component-color;
}

Using @forward will make it simple for you to import multiple files without specifying them separately and instead use the common file.


The above is a basic intro for using @use and @forward. There is much more to it, like Private Members, Index Files, Visibility Control, etc. I’ll be attaching a few references where you could refer to these features in detail.

References