Setting up Element

Working with SASS in Element

Element uses SASS for all of its styles. Specifically, it utilizes SASS' new module system. This document will provide instructions about the proper way to import the Element styles into your application and how to then configure the component styles.

Theming

To theme your application, you have the ability to customize any variable in any of the global sub-packages:

Each sub-package documents all of its variables. To change the value of a particular variable, target the root file of that sub-package via the @use ... with (...); syntax:

@use '@element/global/theme' with (
  $primary: rebeccapurple,
  $secondary: hotpink,
);

@use '@element/global/density' with (
  $default-scale: -1,
);

Project Setup

We recommend that you create a _theme.scss file near the root of your application. This file will be the single place in your application where you override variables for Element packages.

Overrides to global sub-packages should come before overrides to other component packages.

As an example, your _theme.scss file might look something like this:

//
// 1. Configure any desired global sub-packages
//
// --> This could include any of:
// -->   - Density
// -->   - Shape
// -->   - Theme
// -->   - Typography
//
// --> Note: The theme sub-package must be imported
// --> before the typography sub-package can be
// --> configured.

@use '@element/global/theme' with (
  $primary: #0041B3,
  $secondary: #00AAFF,
);

@use '@element/global/density' with (
  $default-scale: 0,
);

@use '@element/global/shape' with (
  $small-component-radius: 2px,
  $medium-component-radius: 4px,
  $large-component-radius: 4px,
);

@use '@element/global/typography' with (
  $styles-headline3: (
    color: red,
  ),
);

//
// 2. Configure any desired component packages
//

@use '@element/button/index' as button with (
  $height: 36px,
);

@use '@element/checkbox/index' as checkbox with (
  $baseline-theme-color: primary,
);

Importing component styles

Each Element component has a root SASS file located at <COMPONENT>/_index.scss. Importing it will include all of that component's variables, mixins, and CSS. This can be done with:

@use '@element/<COMPONENT>';

Using SASS before the module system meant ensuring that you only imported SASS files containing CSS once, otherwise those styles would be duplicated in the output CSS. With the SASS module system, this is no longer a concern. Because of that, we have made each root component SASS file forward all available mixins and variables.

Configuring components

As you may have already surmised from this document, Element components are configured with a combination of SASS mixins and variables.

Mixins

Mixins are used when each instance of a component should be able to be set independently of one another. For example, each instance of @element/sheet should be able to be sized independently of any other sheet you're using, so it exposes a size() mixin.

Using Mixins

Every Element mixin (unless explicitly stated otherwise in its particular documentation) is intended to be invoked under a class specifier that targets the outermost DOM node of the component.

So given the following HTML:

<div class="my-page">
  <aside class="element-sheet element-sheet--right my-sheet">
    <div class="element-sheet__overlay"></div>
    <div class="element-sheet__surface">
      <div class="my-element"></div>
    </div>
  </aside>
</div>

Either of the following mixin invocations would be valid:

@use '@element/sheet';
@use '@element/global/helpers';

.element-sheet {
  @include sheet.size(helpers.space(32), 100%);
}

.my-sheet {
  @include sheet.size(helpers.space(32), 100%);
}

However, the latter should be preferred because it targets a particular instance of sheet instead of targeting every instance of a sheet (of course there are plenty of other ways to do that too).

All of the following mixin invocations would be invalid:

@use '@element/sheet';

// INVALID: Mixins cannot be invoked at the root of the
// stylesheet
@include sheet.size(...);

.my-page {
  // INVALID: Mixins cannot be invoked inside of a parent
  // element of the sheet
  @include sheet.size(...);
}

.element-sheet__surface {
  // INVALID: Mixins cannot be invoked inside of a child
  // element of the sheet
  @include sheet.size(...);
}

.my-element {
  // INVALID: Mixins cannot be invoked inside of a nested
  // child element of the sheet
  @include sheet.size(...);
}

Variables

Mixins have the ability to affect each instance of a component independently. Variables on the other hand make it possible to change every instance of a particular component. The Element Top App Bar for example exposes variables for its various row heights, because we expect these to be consistent throughout an application, and not vary from one usage to another.

$row-height: 64px;
$mobile-row-height: 56px;
$prominent-row-height: 128px;
$dense-row-height: 48px;

Setting the variables

It is possible for you as the user of Element to change the value of any component variable. In order to do that within the SASS module system, you must @use ... with (...); the component's root SASS file at the root of your application before that component is @use'd anywhere else in your application.

@use '@element/global/theme' with (
  $primary: rebeccapurple,
  $secondary: hotpink,
);

@use '@element/top-app-bar' with (
  $row-height: 4px;
  $mobile-row-height: 44px;
  $prominent-row-height: 444px;
  $dense-row-height: 4444px;
);

Now, every future time that you @use the top-app-bar in your application, those variables will be set to the values that you supplied here.

Helpers module

The Element Global package supplies an additional useful SASS module that you can @use including mixins, functions, a media query system with pre-defined (yet configurable) breakpoints. In addition to those, the helpers module forwards the functions and mixins for each of the global sub-packages (density, shape, theme, and typography).

You can import the helpers module with:

@use '@element/global/helpers';

Please see the Element Global documentation for a full explanation of each provided utility.

Sass Error - "Can't find stylesheet to import"

If you're using webpack's sass-loader in order to compile Element's SASS, there's a chance you might run into an error similar to:

ERROR in ./src/index.scss
Module build failed (from ../node_modules/sass-loader/dist/cjs.js):
SassError: Can't find stylesheet to import.
  ╷
1 │ @use '@element/<COMPONENT>';
  │ ^^^^^^^^^^^^^^^^^^^^^^^^^
  ╵

This error is caused by an issue with sass-loader, relating to how webpack resolves file paths. There are two ways to work around this issue:

  1. Disable the webpack importer for sass-loader.

    To do so, in your webpack.config.js, add the following line:

    module.exports = {
     mode: 'development',
     module: {
       rules: [
         {
           test: /\.s[ac]ss$/i,
           use: [
             'css-loader',
             {
               loader: 'sass-loader',
                 options: {
    +              webpackImporter: false,
                   sassOptions: {includePaths: ['node_modules']},
                   implementation: require('dart-sass'),
               },
             },
           ],
         },
       ],
     },
    };
  2. Explicitly path to the _index.scss file that should be implicitly referenced by pathing to a directory.

    To do so, change the following:

    - @use '@element/button';
    + @use '@element/button/index' as button;

    Notice that you now have to also specify the namespace in order to avoid the default index namespace.

Also, see this issue created by Element authors documenting a different side effect of this erroneous webpack path resolution.