designsystemet icon indicating copy to clipboard operation
designsystemet copied to clipboard

Use data attributes for css

Open Barsnes opened this issue 1 year ago • 7 comments

This is a suggestion, and needs to be investigated

Today we have explicit classes for sizes, etc. - but it would be nice if we can have a good developer API for this, even if our users use just CSS classes.

A proposal is to use data attributes like we use props in react, so things like size and variant are the same across all components. This is also how we will do theming, so it plays nicely with that,

Given a button we want to be small. secondary variant and danger color, we would do this:

<button class="fds-btn" data-size="sm" data-variant="secondary" data-color="danger">
button
</button>

Our css would look like this:

.fds-btn { ... }
.fds-btn[data-size="sm"] { ... }
.fds-btn[data-variant="secondary"] { ... }
.fds-btn[data-color="danger"] { ... }

A big plus for doing this is that our users only need to set one class to define the component. It is easy to select, and change a data attribute with javascript, easier than classes:

let value = el.getAttribute("data-size");
el.setAttribute("data-state", "sm");

CSS Trick has a great article about this

Barsnes avatar May 23 '24 07:05 Barsnes

This might be related to #1952

Barsnes avatar May 23 '24 07:05 Barsnes

Do we have an example of other css frameworks that have done this approach?

mimarz avatar May 23 '24 07:05 mimarz

Do we have an example of other css frameworks that have done this approach?

I don't know of any framework that does this currently, I did a quick look and did not find any. Another small plus I thought of, is also the lowered risk of adding multiple classes of the same type, ex.: two variant classes

Barsnes avatar May 23 '24 07:05 Barsnes

If the project wants to eventually move to web components I think this could be done. The attributes would not have to be data attributes, they could simply be any self defined ones in a web component.

I guess most systems like to separate code and styling. Dom attributes deal with everything except styling while the classes are used for styling.

poi33 avatar May 24 '24 10:05 poi33

Most web component + design systems don't use this after some searching. But I found some that do:

  • Redhat https://github.com/RedHat-UX/red-hat-design-system 🌞 Example here: https://ux.redhat.com/elements/button/
  • Nordhealth https://nordhealth.design/components/button/
  • Pharos https://github.com/ithaka/pharos https://pharos.jstor.org/storybooks/wc/?path=/docs/components-button--docs

They all attach it to the root of the web component with a attribute selector :host([variant="secondary"]) button type selectors

Microsoft fluentUI also does this: https://github.com/microsoft/fluentui/blob/master/packages/web-components/src/button/button.styles.ts#L311C5-L311C46 But they have a different solution to generate a stylesheet for each component 🤯

poi33 avatar May 24 '24 10:05 poi33

It seems like React Aria quite a bit image ref

Barsnes avatar Jun 04 '24 06:06 Barsnes

I like this approach, and its also possible to do [data-placement*="top"] to check if data-placement="top left" contains top. JS-wize we can use the el.dataset.placement API as well.

eirikbacker avatar Aug 13 '24 10:08 eirikbacker

Another advantage data-attributes gives us, is a quite similar React and HTML API:

React: <Button variant="primary">
HTML: <button class="ds-button" data-variant="primary">

It also prevents the consumer from adding a invalid combination of classes:

Wrong: <button class="ds-button ds-button--primary ds-button--seconrdary">
Can not go wrong: <button class="ds-button" data-variant="primary">

Considering every class name should be prefixed by component name (i.e. ds-button), rendering data- does not make that big of difference in terms of kilobytes :)

eirikbacker avatar Aug 22 '24 05:08 eirikbacker

We agreed to pursue this way of defining component variants and styling using data attrs in CSS.

Performance is negible in 2024 with classes vs data attr selectors.

mimarz avatar Aug 26 '24 22:08 mimarz

Additional information: we'll use the data-ds- prefix to minimize risk of namespace conflicts

eirikbacker avatar Aug 27 '24 06:08 eirikbacker