How should I approach CSS in my UI Component library?

I’m building a small UI component library for my team to use and I’m a bit stuck on what the best approach to styling out the components is.

At the moment the components have no styling whatsoever and I liked this at first because it meant that they were completely CSS neutral. It didn’t matter if you used Bootstrap, Material, Tailwinds etc. However the drawback of this is every component invocation requires class attributes which gets tiresome and makes the markup cluttered.

Which leaves me a bit unsure. I could obviously classNames the components to bake classes into them but then the library is becoming opinionated in an environment where we might use Bootstrap for one project and Material for another.

I thought of adding default, custom selectors to each component like libraryname-panel-header and then we can either come up with a default css styleguide or it can be left on a per project basis. This has a drawback in you suddenly have to do a load of CSS and that might not be a small job. You also have to ‘learn’ a bespoke catalogue of classes and that might be more of a waste of time.

I’d love to get some insight into how others have approached similar issues and if there is any sort of ‘best practice’ approach for such things.

I do not believe there is a best practice in this case and it comes down to which trade-offs are you willing to live with.

I know for me I always add a classNames: ['name-of-my-component'] for both testing and CSS purposes (exception: tagName: '' components).

There is also the ability to extend components so you could do one of the following to make things easier:

  1. Extend the addon’s components in your app and add your own classNames(classNames merge, not override, during an extend)
  2. Use the component name defined in the original classNames and use CSS pre processing like SASS @extend(Many CSS libs have this setup in mind, ex. tailwind, bootstrap, material)

There my be other solutions too but this is how I approach this topic in my apps/addons.

So thinking through the @extend approach I’d create custom classNames in each component but provide a stylesheet that listed them and gave them an @extend property that made them an extension of an existing bootstrap component.

Another option I considered was to have a config option that gave the library a boolean. Then the classNames could be created by a computed property so if bootstrap =true it’d add the Bootstrap classes in the component etc

That did seem like a lot of code though

Edit: I’m the OP, I didn’t realise I had two accounts with a PC using one each!

Um not exactly what I had on mind. I was thinking more like every component on the addon had a class. Then in the app that consumes it they could use their choice of CSS processor to customize.

I was using @extend as an example on how to apply bootstrap. Like:


// app/styles/app.scss

.my-component {

@extend .btn;

}

What’s the purpose of the UI component library?

(The original post suggests these components could be used with different CSS frameworks like Bootstrap and Material, which makes me think it’s not as much about styling as it is about functionality. Is that correct?)

2 Likes

That’s exactly right. In fact the videos you and Ryan produce at Ember Map are a major inspiration behind developing this library for my team.

At the moment I am taking an approach similar to @sukima. The components have classNames wired into them that should be unique enough to conflict with any frameworks.

I was considering as part of the addon adding a default-components.scss file with some basic styling and an empty-components.scss that has a list of the custom classes but are just blank so they can be styled at will. That way you should be able to use @extend, mixins or just hard code whatever you need per project.

1 Like

In this case I would probably try to make them renderless components, and be completely unopinionated about the styling. Then you could provide some examples of how to use them with Bootstrap, Material, etc.

Consuming apps would then wrap your renderless component in a branded component so they’re easy to reuse in that app.

Let me know if that makes sense or if an example would help!

You’ve said a lot in this post.

“makes the markup cluttered” - that’s a tradeoff for dev convenience, and unless you have a specialized CSS person on your team, should be a tradeoff worth considering IMO.

I add the component name as the CSS class name to all of my components by default. Now, this means that my UI addon has to have meaningful names, so there’s that to think about, but I find that the dev speed is so much faster when I do this. I’ve lowered a cognitive barrier and given myself one less thing to think about.

You could use something like ember-theme-changerr to create your UI addons, and then create a theme for each set of CSS that you want to have. If I needed to support a UI component addon with multiple themes, this is how I would approach it. This will also give you the room to make a default style that can be used for demo purposes.

1 Like