DEV Community

Cover image for @use & @forward in SASS
Vaibhav Mehta
Vaibhav Mehta

Posted on • Edited on

29 4

@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
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

@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;
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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.
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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

// _my_component.scss
.my-component {
  color: $component-color;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

Tweaking the component file a bit:

// _my_component.scss
.my-component {
  color: c.$component-color;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

// helpers.scss
@forward 'colors';
@forward 'fonts';
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (3)

Collapse
 
leongeldsch profile image
Leon Geldschläger

Good article! I was just wondering if it would be possible to conserve the namespaces of the individual files when using @forward ?

Collapse
 
dinodonga_76 profile image
dinoDonga • Edited

Good read!
Only thing i would change is to rename the helpers file into _index.scss
if you then @use from vars you don't have to specify the name which makes it imo a little more semantic

/project
|-- /components
|---- _my_component.scss
|-- /styles
|---- _colors.scss
|---- _fonts.scss
|---- _index.scss // importing from vars/ will automatically look for an "index" file
|-- index.scss
Enter fullscreen mode Exit fullscreen mode

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

.my-component {
    color: helpers.$component-color;
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
phamthanggg profile image
phamthanggg

thank you, it very clear, concise and useful

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more