DEV Community

Cover image for Meet Sass Pal.
Alain D'Ettorre
Alain D'Ettorre

Posted on

Meet Sass Pal.

So, SASS has variables, mixins, functions, parent selectors, nesting. Cool. That gives developers more power, not more structure.

You could npm install bootstrap and import just its sass files into your frontend project. Now you have pre-made components, some variables, utilities. You later realize you don't need all those unused components, so you start to comment out some @import statements. Then you want to change the color palette and override variables. Then you want buttons to look different and add CSS to override the framework's CSS. You may reach a point where you use only Bootstrap's utilities.

You swear you're not gonna use frameworks again and instead switch to a utilities-only library, Tailwind, which is a fully composable way of avoiding to write any CSS and instead stuff your templates with hundreds of utility classes. It has its strengths though: it's good to have everything on the table and just pick up what you want, but it can be tiresome to set up a huge regex via PostCSS and purge everything when you're finished. Try to do that with Angular and let me know (EDIT: this has improved in the last year).

Meet Sass Pal, a Sass library that attempts to solve most of these problems. The main concepts include

  • Not a single line of CSS is output unless you need it
  • Sensible defaults for colors, media breakpoints and units
  • Helps to centralize shared values into a store
  • Completely overridable and extensible
  • No pollution of global namespace: only one $_PAL_STORE variable exists and all mixins and functions start with pal-
  • Gradual migration: you can use as little as needed or go full Sass Pal without colliding with any existing styling code
  • A suite of unit tests and a comprehensive documentation with examples

The cool part is that is has a lot of features like builders, request maps, device queries, a store and reducers (high five to Redux enthusiasts out there), but you can still ignore everything and just use a tiny fraction of it, since all disappears once compiled to CSS. Let's peak into the docs. So this

.hello-world {
  @include pal((

    'any': (
      space: my2 'p^b4',
      border: (x: 2 #ccc, y: 1 #ddd),
      position: absolute (2 4),
      size: (

    'tablet+': (
      space: my0 py5 px8,
      border: (x: 3 #ccc, y: 3 #ddd),

    'desktop+:hover': (
      space: my2

Enter fullscreen mode Exit fullscreen mode

compiles to this

.hello-world {
  margin-top: 1rem;
  margin-bottom: 1rem;
  padding-top: 2rem;
  padding-right: 2rem;
  padding-left: 2rem;
  border-right: 1rem solid #ccc;
  border-left: 1rem solid #ccc;
  border-top: 0.5rem solid #ddd;
  border-bottom: 0.5rem solid #ddd;
  position: absolute;
  top: 1rem;
  bottom: 1rem;
  left: 2rem;
  right: 2rem;
  width: 75%;
  height: 4rem;
  min-width: 50%;

@media screen and (min-width: 768px) {
  .hello-world {
    margin-top: 0;
    margin-bottom: 0;
    padding-top: 2.5rem;
    padding-bottom: 2.5rem;
    padding-right: 4rem;
    padding-left: 4rem;
    border-right: 1.5rem solid #ccc;
    border-left: 1.5rem solid #ccc;
    border-top: 1.5rem solid #ddd;
    border-bottom: 1.5rem solid #ddd;

@media screen and (min-width: 1024px) {
  .hello-world:hover {
    margin-top: 1rem;
    margin-bottom: 1rem;
Enter fullscreen mode Exit fullscreen mode

For me, the best part is not that you write less code, but that you can separate the actual styling (inside the components) from the state management of your styling values (inside your store). Like, what does 'desktop+:hover' mean in the example? Basically, whatever you want it to mean. By default, anyway, it means these rules only apply to desktops or bigger devices, only while hovering, where a desktop is just a name you give to a resolution range you can override. What does side: (w-3/4, h-8u) mean again? It means I want this component to have a width of 75% of its container and an height equal to 8 times the base unit and the base unit is 0.5rem by default or any other number if you override it.

To learn more, visit

Photos courtesy of

Top comments (0)