Encapsulated styles for a story in Angular Storybook

42 Views Asked by At

Question How can I have specific scss files loaded for individual stories?

Details I am using Storybook 7 with Angular 17 to document a component library. There's 1 global stylesheet with a couple components that are styled slightly differently based on the brand. For consuming applications, those differences are handled via a couple different imports based on the brand. However, I cannot do this in Storybook because all the styles are global – the small differences in styles would both be loaded, thereby conflicting.

One way I have tried managing this is by creating "wrapper" components and using Angular's ViewEncapsulation to capture those style differences

These components are at the path: stories/typography/wrapper/, whereas most of the other styles are in a base global styles directory.

import { Component } from "@angular/core";


/**
 * This component is needed so we can load the different styles
 * for the different themes as needed
 */
@Component({
    selector: "typography-wrapper",
    styleUrls: ["./typography-wrapper.styles.scss"],
    template:`<ng-content></ng-content>`
})
export class TypographyWrapper {}

@Component({
    selector: "typography-v2-wrapper",
    styleUrls: ["./typography-v2-wrapper.styles.scss"],
    template:`<ng-content></ng-content>`
})
export class TypographyV2Wrapper {}

And the styles:

// "./typography-v2-wrapper.styles.scss"

@import "styles/brand2/variables";
@import "styles/brand2/mixins";
@import "styles/brand2/components/type";
// "./typography-wrapper.styles.scss"

@import "styles/brand1/variables";
@import "styles/brand1/mixins";
@import "styles/brand1/components/type";

Any help would be appreciated.

1

There are 1 best solutions below

0
Naren Murali On

You can add a class at the root component that will determine which style sheet group to use. In your app.component.ts you could add the class that determines which style to use!

You need renderer2 for adding the body class.

 ....
 constructor(private renderer2: Renderer2) {}
 ...
 ngOnInit() {
    const brandClass = isBrand1 ? 'brand1-styles' : 'brand2-styles';
    this.renderer2.addClass(document.body.parentElement, brandClass);
    this.renderer2.addClass(document.body, brandClass );
 }
 ....

and your stylesheet can be defined as

/ "./typography-v2-wrapper.styles.scss"

.brand2-styles {
    @import "styles/brand2/variables";
    @import "styles/brand2/mixins";
    @import "styles/brand2/components/type";
    // "./typography-wrapper.styles.scss"
}

.brand1-styles {
    @import "styles/brand1/variables";
    @import "styles/brand1/mixins";
    @import "styles/brand1/components/type";
}

Note: @import might be deprecated in future so go for @use which is going to be the replacement for it!