suitcss / suit

Style tools for UI components
http://suitcss.github.io/
3.8k stars 225 forks source link

[question] Theming a group of components #140

Closed danturu closed 7 years ago

danturu commented 7 years ago

I have a group of components Menu, MenuSection and MenuItem. Technically each component is standalone and isolated, but 99% of the time it's a composition:

<Menu>
  <MenuItem ...>    
  <MenuItem ...>
  <MenuItem ...>
</Menu>

Let's say I add an invert modifier to Menu that affects only the component's and it's descendants color palette.

Should I add the invert for each component like:

<Menu invert>
  <MenuItem invert ...>    
  <MenuItem invert ...>
  <MenuItem invert ...>
</Menu>

...or there's a better way? What is the SUIT way? :-)

simonsmith commented 7 years ago

I think you're on the right track. By applying the invert prop separately you can use the React.Children helper to offer an elegant solution:

  const Menu = ({children, invert}) => {
    return (
      <div className="Menu">
        {
          React.Children.map(
            children,
            child => React.cloneElement(child, {invert})
          )
        }
      </div>
    );
  };

Now you can use your Menu component like so:

<Menu invert>
  <MenuItem ... />    
  <MenuItem ... />
  <MenuItem ... />
</Menu>

The invert prop will be merged in with any other props you pass to the children and MenuItem remains decoupled from its parent. More info in this article

This was probably more of a React answer than a SUIT one. It might need some different thought if we're dealing with simple HTML structures.

Hope that helps

giuseppeg commented 7 years ago

If you are using React there are many ways to do so. @simonsmith's will affect only the direct children. If you want the entire subtree to be affected you'd need to be a bit more creative and the solution is slightly more complex (could use a pub/sub mechanism to mimic css custom properties for example).

If, instead, you are using plain SUIT CSS then modifiers are the way to go.

.Menu--invert .Menu-item {
  color: hotpink
}
danturu commented 7 years ago

Thank you for the answers! @simonsmith's solution fits my requirements, i.e. I don't want to make things complicated so I have to pass invert only to the direct children.