Web components and shared styles
Asked Answered
T

3

10

This is one of those "what should we do about this"-questions. As you know, web components are supposed to be small, contained applications for websites. However, sometimes these needs to be styled depending on the site they're embedded on.


Example: "Sign up to our newsletter"-component. This component would have a few key items:

  • An input box
  • A button
  • Maybe recaptcha
  • A method that talks to your service once the button is pressed (passing in the email)

We're going to use Google and YouTube as examples. Google's color scheme is blue (let's imagine that) and YouTube's color scheme is red. The component would then be something like <newsletter-signup></newsletter-signup> on the page you're embedding it in. Both Google and YouTube have this.

The problem comes in, when the component needs to inherit the styles from Google and YouTube. A few deprecated CSS selectors would be great for this, because Google and YouTube's style sheets could simply enable colors for the Shadow DOM, so we wouldn't have to copy/paste the styles. The component should theoretically not know anything about the styles from the host, because we want it to inherit from the host (Google and YouTube).

At the moment, I'm creating a web component using Angular 6, which has a lot of styles, because it has a lot of elements. I'm copy/pasting styles, Bootstrap, icons, and so on from the host site, then styling them based on <newsletter-signup brand="google"></newsletter-signup>. So if the brand is Google, the colors should be red, for example.

This is really bad, because of a few reasons:

  1. Styles have to be updated on both the web component and on the host
  2. Duplicated code is never a good idea
  3. If all the styles are copied 1:1, the amount of bytes required for styles is doubled

How would I, as a developer, take this into account? How do I make styles on the host, then apply them on my web component (call it inheritance)? I'm sure someone has had the exact same problem with Shadow DOM as I am experiencing. Thanks for reading.

Terisateriyaki answered 19/10, 2018 at 12:43 Comment(0)
M
2

I realize you do not want to write same kind of rules for your common component(selector)

i.e. you want to do styling as where your common selector is placed.

Things you can do to handle this:

1. Create your own logical css framework

Write most commonly used CSS rules in global css.For example if you have integrated bootstrap and you want to override bootstrap, you will write most common overrides in app.css which overrides bootstrap.

"styles": [
          "node_modules/bootstrap/dist/css/bootstrap.min.css",
          "src/styles/app.scss"
        ],

This app.scss should be written in way to which you can override.

  1. Send Rules as input

send custom rules Obj and use in elements you want to override.

<newsletter [input]="customRulesObj"></newsletter>

component.ts

customRulesObj = new CustomRulesClass();
customRulesObj.color = 'red';

You can send rules in input in various component by creating a common class as you know where you are embedding this component.

  1. Extend this component from a common component

If you are too concerned for css you can extend your component from a common component which provides you with css logic as per need.

export class NewsLetterComponent extends CSSComponent implements OnInit
  {


  }

css-component.ts

In this component can logically define css as per host, current routerlink and other multiple if else condition. You can define rules by switch case conditions and bind those rules to component you have extended.

Mercedezmerceer answered 28/10, 2018 at 18:7 Comment(1)
One problem is that my host (the page where I'm including my web component) should share the styles. As far as I know, you cannot include an external resource in the "styles" array. I couldn't get it to work. I'll provide an answer to what I did to solve some of these issues.Terisateriyaki
T
1

One of the biggest must-do's of web components is: My host (page where I'm embedding my web component) should not depend on the web component nor know about the web component.

What this basically means: Styles of my web component should not be shared with the host.

If my host decides to update the styles, it should affect my web component. Not the other way around. To solve this, I imported the external styles from my host directly inside the CSS file using @import. Here's an example:

import url("https://my-host.com/styles/core.css");

my-component {
    //all styles goes here
}

I did this using SASS but can be done using regular CSS.


This is not a great solution at all, but it does what I want: Inherit the styles from the host. Although I would have to import every stylesheet there is, it still works.

A downside to my solution: When I load the page, it will send a request to the style from the <link> element inside the <head>-tag my host, but also to the style inside my import. So the styles are loaded twice. For our application, which is internal use only, it doesn't matter if we request additional ~200 KB data.

Terisateriyaki answered 29/10, 2018 at 7:32 Comment(3)
the css file should be cached and then only downloaded once. Note that now there's a new feature called "constructable stylesheet for your needs: https://mcmap.net/q/1088761/-share-style-across-web-components-quot-of-the-same-type-quot/4600982Shears
Constructible stylesheets are still not supported in all browsers :(Somatotype
Not only are the stylesheets loaded using import loaded twice, they're also loaded synchronously so it's not optimal there eitherSomatotype
M
0

This question is a few years old and the situation has changed. The way to share styles with web components is now to use link tags to a shared stylesheet.

Inside each component:

<link rel="stylesheet" href="https://my-host.com/styles/core.css">

Reference: https://github.com/WICG/webcomponents/issues/628

Minute answered 8/2, 2022 at 18:54 Comment(1)
This is not a long term solution. Constructible stylesheets are.Somatotype

© 2022 - 2024 — McMap. All rights reserved.