@use & @forward in SASS

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, has to offer two new ways of importing them, namely @use and @forward.


Important 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;
}

Note @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
}

Note 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 helper.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

Create a Free Account

Create an Account View Pricing