1

I would like to create a function that gets 2 variables as input and, if the first one exists, returns that variable and if not, it returns the fallback value.

I was trying this

@function component-token($token-name, $fallback) {

  @if variable-exists($token-name) {
    @return $token-name;
  } 

  @return $fallback;
}

And I wanted to use it as

.my-class {
  color: component-token($component-button-primary-color,  $color-primary-base);
}

However, this poses two problems:

  • variable-exists expects a string to be passed in.
  • If $component-button-primary-color does not exist, compilation fails.

I tried calling the function by passing in a string, as such

.my-class {
  color: component-token(component-button-primary-color,  $color-primary-base);
}

but this left me with color being the string component-button-primary-color, which is of course not what I want.

To give a little bit of context, we're preparing a project for multibranding, in which we want to have our CSS have a base set of values, but every value should be overwriteable by a brand.

In the example above, we can assume that a brand will always have $color-primary-base. But a brand can also define the $component-button-primary-color variable, which should then overwrite the value.

Our first approach was going with !default as can be seen here. But this brings a lot of boilerplate, will require a lot of context switching because you can't find the needed information in the one line.

Any idea?

JDansercoer
  • 447
  • 1
  • 5
  • 16

2 Answers2

2

You can use optional parameters to get the required result. Required parameters must precede optional parameters.

@function button-color($color-primary-base, $color-primary-button: null) {

    @if $color-primary-button != null {
        @return $color-primary-button;
    }

    @return $color-primary-base;
}

I changed the code / names to match your use case : changing the color of a button.

The caller:

$customer-color-primary-base : red;
$customer-color-primary-button: green;

button {
    color: button-color($customer-color-primary-base, $customer-color-primary-button);
}

As you can see, it does not require a string as parameter.

You can experiment with keeping the parameters empty or not providing the optional parameter at all:

$customer-color-primary-button: null;

or

color: button-color($customer-color-primary-base);

it does allow you to change the variable later on (dynamic props are not possible, but it is possible to decalare it with a null value at first):

$customer-color-primary-base : red;
$customer-color-primary-button: null;
$customer-color-primary-button: green;

.button {
    color: button-color($customer-color-primary-base, $customer-color-primary-button);
}
0

You can never call the mixin with an undefined variable. What you can do is make sure it exist just before calling the mixin and give a default value of 'false', for example.

EDIT: Another choice is to use a map or list to store the colors, instead of using regular variables, like so:

$color-primary-base: red;

$colors: (
  component-button-primary-color: #007dc6
);

@function component-token($token-name, $fallback) {
  
  @if (map-has-key($colors, $token-name)) {
    @return map-get($colors, $token-name);
  }
  @return $fallback;
}

.my-class {
  color: component-token(component-button-primary-color,  $color-primary-base);
}

.my-class-2 {
  color: component-token(unexistent-key,  $color-primary-base);
}
alotropico
  • 1,904
  • 3
  • 16
  • 24
  • But that's the issue we would like to solve, because, as stated, the other best approach would be to go with `!default` but that just feels super boilerplaty. – JDansercoer Sep 05 '20 at 07:10
  • If you call the mixin with an undefined variable that's when you're getting the error, so you can't fix the error within the mixin that comes afterwards. You would have the same problem with any programming language, you just can't use undefined variables to call a function or, in this case, a mixin – alotropico Sep 05 '20 at 07:15
  • That I fully understand. But is there no way to access the variable based on the string? Because we can do the `variable-exists`, so we know if it exists. Is there a way in SASS to construct a variable based on a string? – JDansercoer Sep 05 '20 at 07:16
  • Unfortunately it's not possible https://stackoverflow.com/questions/8533432/creating-or-referencing-variables-dynamically-in-sass – alotropico Sep 05 '20 at 07:22
  • I edited the answer with a solution inspired by the accepted answer to the question I linked above, that would certainly be a much more neat way, hope it helps – alotropico Sep 05 '20 at 07:34