Skip to content

mrac/decoupled-styling-css-modules

Repository files navigation

Decoupled styling

Solution - React + TypeScript + CSS-Modules

Stack

Goals

Mission statement:

Decoupling from styling for UI-components should be on similar level as in native HTML/CSS (HTML element is decoupled from its styling by exposing an API to inject styling via class attribute or className property).

Requirements:

  1. UI component is decoupled from its styling. Styling is injected into the component via its API.
  2. UI component has its default, minimal styling, in case no styling is injected.
  3. Default styling may be overwritten by custom styling via styling-API.
  4. Default styling absent from the styling-API, can be also overwritten (although "unsafely", with regards to SemVer).
  5. Styling can be set for the UI-component and its children (and grand-children etc.)
  6. It's possible to customise the styling for the whole application in one run (styling theme).

Additional requirements (no steps backwards):

  1. UI components styles are isolated (no name-conflicts, styles don't leak-in and out)
  2. No implicit dependencies to styles
  3. UI components should be decoupled from each other, as far as possible

Solution

Examples of usage:

To simplify examples, global CSS-classes are used.

  1. Native element with default styling:
<textarea />
  1. UI-Component with default styling:
<MyButton />
  1. Native element with custom styling (pass a CSS-class):
<textarea className="center" />
  1. UI-Component with custom styling (pass an object containing CSS-classes):
<MyButton classes={rootPosition: "center", content: "fixed-width"} />

It's up to the component itself to expose its styling-API.

  1. Higher-level component (nested objects containing CSS-classes to overwrite children styles):
<App classes={title: "big", okButton: {rootPosition: "left"}} />

Demo

MyButton component

Higher-level - App component

Application-level - themes

Customisation

  • To make nested component customisation possible with CSS Modules, the nested() function is used in components to construct nested-object styling-API from flat CSS files. CSS Modules don't support nested component's customization yet - see issue.
  • Overwriting component's default styles is done "per class" (instead of "per CSS-property" like natively in CSS). In case there is need to alter just one CSS-property, it's possible to use composition like here in app component.
  • native CSS overwriting solution by CSS Cascade is not used (unless composition is used). CSS-classes are not combined, but simply replaced if customised.
  • when composition is applied, CSS Modules does not copy the styles but concatenates selectors to extend styles

About

Solution for UI-components decoupled from styling

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published