1
votes

This question likely has no single direct answer, but hopefully will lead to some best practices or common patterns to use when adapting an existing styles framework to new web component development.

For my case, I have a component <custom-avatar>, and it's all set up properly with self-contained styles and functionality, everything is just peachy.

In certain use cases, the application display needs to stack avatars, just one slightly overtop one other at a diagonal, and the pattern I'm following is using a simple component <custom-composite-avatar>. All this does is wrap the slotted content in a <div> with the correct styling class, but key aspect is retaining the composability for flexible re-use, like so:

<custom-composite-avatar>
  <custom-avatar title="first"></custom-avatar>
  <custom-avatar title="second"></custom-avatar>
</custom-composite-avatar>

The tricky bit lies in the styles, which are imported from a monorepo that provides the same BEM-ish CSS and component CSS modules to other flavors of the component library like React, Vue, etc. I have the avatar and composite-avatar styles imported just fine, but forcing the intended overlap display is defined with the hierarchical selector .my-composite-avatar.my-composite-avatar--medium .my-avatar {}

So with .my-composite-avatar class applied to the div wrapper within <custom-composite-avatar> and the .my-avatar class applied to the wrapper within the <custom-avatar> and it's own Shadow DOM, that parent/child CSS selector is no good.

I doubt there is a silver bullet for this, but this seems like it will be a rather common scenario as more people migrate to Web Components while using existing styling systems. What approach makes the most sense to ensure that the composite component remains composable, and adaptation of existing selectors pain-free (or at least easy to communicate to other devs)? can this be solved with ::host or ::slotted, or will these cases require significant re-work?

Thanks for reading, your ideas are appreciated!

1

1 Answers

3
votes

I would advice to become good friends with CSS properties
because they trickle down into shadowDOMs following CSS selectors.

example

I have an <SVG-ICON> element taking configuration from attributes OR CSS properties
with my favorite lines of code:

let val = this.getAttribute(attr) 
           || 
          getComputedStyle(this)
           .getPropertyValue("--svg-icon-" + attr)
           .replace(/"/g, "")
           .trim();

Allows for your standard attribute configuration:

  <svg-icon name="configuration" fill="grey"></svg-icon>

But more powerful (simplified example):

  <style>
    body {
      --svg-icon-fill: "grey";
    }
    svg-icon[selected] { 
      --svg-icon-fill: "green";
    }
  </style>
  <svg-icon name="messages" selected></svg-icon>
  <svg-icon name="configuration"></svg-icon>

CSS = Custom String Scripting

It doesn't often happen, but sometimes the simplest code makes me very happy.

There is no Styling restriction!

These 2 lines allow any String you want in CSS properties:

    .replace(/"/g, "")
    .trim();

Example

<style>
   [name*="globe"] {
      --svg-icon-tile: "rect:0,0,24,24,0,fill='blue'";
      --svg-icon-stroke: white;
   }
</style>
<svg-icon name="feather-icons-globe"></svg-icon>

The --svg-icon-tile has nothing to do with CSS, it is read (and parsed) by the <SVG-ICON> connectedCallback() code to generate a SVG background/tile for all icons named globe.

The double-quotes aren't required, but without them your IDE will complain about invalid CSS.

Have fun coding... you will pull some hairs when you start with calc() in your CSS properties...
But you can take 'CSS' to another level.

PS.

And monitor the future of ConstructAble StyleSheets aka ConstructIble StyleSheets aka Constructed Sheets aka AdoptedStyleSheets:

iconmeister