Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow styling of components #142

Closed
lorensr opened this issue Mar 2, 2017 · 11 comments
Closed

Allow styling of components #142

lorensr opened this issue Mar 2, 2017 · 11 comments

Comments

@lorensr
Copy link

lorensr commented Mar 2, 2017

Both of these, when rendered, become an unstyled div:

import Paper from 'material-ui/Paper'

<Paper>
                <style jsx>{`
                  div {
                    background: red;
                  }
                `}</style>
</Paper>
<Paper>
                <style jsx>{`
                  Paper {
                    background: red;
                  }
                `}</style>
</Paper>

It would be nice if there were a way to style the div that <Paper> becomes.

@zachdixon
Copy link

I was able to accomplish something similar via global selectors. For example

<div className="root">
    <Paper className="my-paper">
    ...
    </Paper>

    <style jsx>{`
        .root :global(.my-paper) {...}
    `}</style>
</div>

.root will have the scoped selector, but .my-paper won't, so I believe it basically turns the rule into something like:
.root[data-jsx="1234"] .my-paper {...}

@lorensr
Copy link
Author

lorensr commented Mar 8, 2017

Thanks, that works. Would be nice to have something simpler like my examples though.

@rauchg
Copy link
Member

rauchg commented Mar 8, 2017

@lorensr I'm trying to stick as much as possible to "just CSS". Since we're inverting the CSS model (everything is scoped by default, no globals), we needed syntax for opting into globals, and that's the only reason I broke that rule with :global.

So, arguably our current solution is simpler, just not necessarily easier. I'd be open to exploring that model though in other modules, or maybe a fork of styled-jsx, and see how it goes. There's a lot to explore. Thank you

@rauchg rauchg closed this as completed Mar 8, 2017
@rauchg
Copy link
Member

rauchg commented Mar 8, 2017

Thanks @zachdixon for helping out. I purposefully also put this example in the README, referencing how I'd style react-select:

image

https://github.com/zeit/styled-jsx#global-selectors

@cdeutsch
Copy link

This still really needs improvement (or you should switch away from styled-jsx)

When you're using something like material-ui and you need to make a tiny tweak, it's not uncommon for the whole component to be nested components; and there are zero acceptable ways to style it with styled-jsx

@fev4
Copy link

fev4 commented Feb 10, 2020

Is there a chance to reopen this?

Possible use case is individually styling one off components without impacting the styles globally.

I managed to do this by using css.resolve from styled-jsx/css but I'm totally unsure if that's the way to go.

@oliviertassinari
Copy link

oliviertassinari commented Jun 10, 2020

We recently had this request in mui/material-ui#20787:

The best solution I could come up with is to do:

import React from 'react';
import Typography from '@material-ui/core/Typography';

export default function Index() {
  return (
    <div className="root">
      <Typography variant="h4" component="h1">
        Next.js example
      </Typography>
      <style jsx>{`
        .root :global(h1) {
          background: red;
        }
      `}</style>
    </div>
  );
}

Capture d’écran 2020-06-10 à 15 21 38

which is basically what was proposed 3 years ago by @zachdixon in #142 (comment). Note that I have used this starting point: https://github.com/mui-org/material-ui/tree/master/examples/nextjs.

@eric-burel
Copy link

eric-burel commented Jun 26, 2020

Hi, I also struggle to find the best pattern to handle global styling. I try to favour styled-jsx against Material UI as much as possible, so I can mix non material-ui components with mui components and have consistent styling.

This is how I try to define the global style, and override MUI defaults.

const AppLayout = ({ children }: AppLayoutProps) => (
  <div className="global-style">
    {children}
    <style jsx global>{`
      .global-style h1, .global-style .MuiTypographi-h1 {
        font-size: 3.815em;
        /* 61px */
      }
      h2, .MuiTypography-h2 {
        font-size: 2.441em;
        /* 29px */
      }
...

The first one will work, but feels clumsy. A palliative would be using PostCSS, which allows a cleaner nesting. Ok, but not really simple.

The second one won't have enough specificity, Material UI style is added later in the tree so I can't override it.

Third alternative is using theme overrides. Works perfect, but it makes me duplicate my style, both for .MuiTypography-h1 (using overrides) and h1 (using styled-jsx global mode).$

Any thoughts on this?
Could nesting happen in styled-jsx to simplify drastically the syntax for such use cases, as we would do in Styled Components?

@eric-burel
Copy link

eric-burel commented Jun 26, 2020

PostCSS with nesting is better, as you just wrap the whole style with a class to get +1 specificity, but breaks VS code. There does not seem to be a "styled-jsx + postcss" plugin yet. Basically the downside is the need to use another 3rd party lib.

<div className="global">
    {children}
    <style jsx global>{`
      .global {
        /* All your styles here, now they have correct specificity + will apply to nested children*/
        h1, .MuiTypography-h1 {
          font-size: 16px;
        }
...

Same pattern applies to "scoped" style that you may want to apply to children.

Edit: just for the record, it works fine with Storybook too, by just setting up Babel config and post css config correctly for the whole project. Haven't really tested with Jest yet but it did not seem to break my tests.

Edit 2: I guess you also have to keep the ".global" className unique each time you use this pattern. In my scenario it could be .layout_appLayout. You could use the component path_componentname for instance. Otherwise you may have clashes, since you use the global option.

Edit 3: using & I don't seem to need a className:

      <style jsx>
        {`
          & :global(.MuiButton-root) {
            color: ${someColorFromCustomProps};
          }
        `}
      </style> 

The & seems sufficient to isolate the component. If I remove it, there are clashes between instances of the same component, if I add it everything is fine.

@eric-burel
Copy link

eric-burel commented Jul 3, 2020

Actually when I don't use a div wrapper, it doesn't work.

export const Button = (props: ButtonProps) => {
  const { preferredTechnology, ...muiButtonProps } = props;
  return (
    <MuiButton
      {...muiButtonProps}
      className={clsx("vns-button", props.className)}
    >
      {props.children}
      <style jsx>
        {`
          & :global(.MuiButton-root) {
            color: ${technologyToColor[preferredTechnology] || colors.blueNext};
          }
        `}
      </style>
    </MuiButton>
  );
};

Also tried a simpler style, eg button { color: red }, it is not applied to the button generated by Material UI.

image

It works if I use a basic HTML button however, so the style or my components do not seem to be faulty.

@oliviertassinari do you have any insight on this? Your example is using a div, so it works ok, but I do not find a pattern that works eg if you wanted to render the Typography directly in order to create a "StyledTypography".

(I also tried using a fragment but then styled-jsx has nothing to attach the class to)

Edit: I think having a wrapping span or div is mandatory, but at least solves the issue. It does not feel very clean however.
Edit 2: after a few more tries, I indeed can't find a solution without a wrapper element :(

@oliviertassinari
Copy link

after a few more tries, I indeed can't find a solution without a wrapper element :(

@eric-burel I came to the same conclusion when experimenting with different options.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants