Access parent selector in SCSS
Table of contents
Problem
Let's imagine that we need to cover a special case in SCSS when an HTML element has two specific classes.
For example, we have a simple React component that accepts two props: type
and size
. Each prop is reflected in the HTML as a class.
import React from 'react';
import './Icon.scss';
import classnames from 'classnames';
export const Icon = ({ iconType, iconSize }) => {
const iconClasses = classnames({
icon: true,
[`icon--${iconType}`]: iconType,
[`icon--${iconSize}`]: iconSize,
});
return <div className={iconClasses} />;
};
By requirements, we need to specially style the icon when it has both icon--right
and icon--big
classes.
@use 'svg';
.icon {
width: 100px;
height: 100px;
background-color: #000;
@include svg.mask(
url('https://raw.githubusercontent.com/rodion-arr/blog/main/content/images/2023/08/colorize-svg/arrow.svg')
);
&--right {
transform: rotate(180deg);
// here we have a duplication of ".icon" selector that we already have above
&.icon--big {
width: 150px;
height: 150px;
}
}
}
The problem is that in the &.icon--big
selector we have a duplication of .icon
selector that we already have above. We can't access .icon
with SCSS parent selector (&
) because we already nested deeper in &--right
.
In case we will update .icon
selector, we will need to update &.icon--big
selector as well which can be easily missed.
Solution
To avoid duplication of .icon
selector, we can use a special SCSS hack that allows us to access the parent selector in nested rules.
We can store a reference to the parent selector in a variable like this: $root: &;
and then use it in nested rules with the help of interpolation: &#{$root}--big
.
So our example will look like this:
@use 'svg';
.icon {
// parent class reference is stored in $root variable
$root: &;
width: 100px;
height: 100px;
background-color: #000;
@include svg.mask(
url('https://raw.githubusercontent.com/rodion-arr/blog/main/content/images/2023/08/colorize-svg/arrow.svg')
);
&--right {
transform: rotate(180deg);
// now we can access parent selector with $root variable
&#{$root}--big {
width: 150px;
height: 150px;
}
}
}
This way we can avoid duplication of .icon
selector and easily update it in one place.
Source code
A live example of this solution can be found on Stackblitz.