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

Supply css class to 3rd party lib without using the name "className" #2076

Closed
vensa-albertgao opened this Issue Oct 9, 2018 · 13 comments

Comments

Projects
None yet
4 participants
@vensa-albertgao

vensa-albertgao commented Oct 9, 2018

Environment

System:

  • OS: macOS High Sierra 10.13.6
  • CPU: x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
  • Memory: 167.45 MB / 16.00 GB
  • Shell: 3.2.57 - /bin/bash

Binaries:

  • Node: 8.11.3 - ~/.nvm/versions/node/v8.11.3/bin/node
  • Yarn: 1.10.1 - ~/.nvm/versions/node/v8.11.3/bin/yarn
  • npm: 6.4.1 - ~/.nvm/versions/node/v8.11.3/bin/npm

npmPackages:

  • styled-components: ^3.4.9 => 3.4.9

Preparation

Create an app with create-react-app,

Change the App.js to this:

import React, { Component } from "react";
import "./App.css";
import styled from "styled-components";

const MyPart = ({ pClassName }) => (
  <p className={pClassName}>this is the P tag</p>
);

const StyledMyPart = styled(MyPart).attrs({
  pClassName: "for-p-tag"
})`
  &.for-p-tag {
    font-size: 60px;
  }
`;

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <StyledMyPart />
        </header>
      </div>
    );
  }
}

export default App;

Steps to reproduce

  1. Run the app, expect the P tag to be displayed as 60px, but it's not.
  2. Change the code to this:
const MyPart = ({ className }) => (
  <p className={className}>this is the P tag</p>
);

const StyledMyPart = styled(MyPart).attrs({
  className: "for-p-tag"
})`
  &.for-p-tag {
    font-size: 601px;
  }
`;
  1. Run the app, now it works.

What is the problem

How to make the styling work when the prop name is not className?

About it

Asked this previously on Stackoverflow.com without any luck. https://stackoverflow.com/questions/52378924/use-styled-components-to-supply-a-css-class/52441187#52441187

If the name of the prop is not className, it won't work.

Don't know if I did anything wrong, but I tried many ways.
Is this just not supported or I miss something? Thanks.

@probablyup

This comment has been minimized.

Show comment
Hide comment
@probablyup

probablyup Oct 9, 2018

Contributor

Why can't you use className? We're generating CSS classes, so that prop must be used and attached. If you need to compose multiple classNames (ours and yours), you can use a helper library like https://github.com/JedWatson/classnames to make it easier.

Contributor

probablyup commented Oct 9, 2018

Why can't you use className? We're generating CSS classes, so that prop must be used and attached. If you need to compose multiple classNames (ours and yours), you can use a helper library like https://github.com/JedWatson/classnames to make it easier.

@probablyup probablyup closed this Oct 9, 2018

@Albert-Gao

This comment has been minimized.

Show comment
Hide comment
@Albert-Gao

Albert-Gao Oct 9, 2018

Because the third party lib requires two separate props for handling two different parts of styles. Composing won’t help here because it won’t work as different classNames will apply to different parts of the DOM.

So styled component doesn’t support this use case?

Albert-Gao commented Oct 9, 2018

Because the third party lib requires two separate props for handling two different parts of styles. Composing won’t help here because it won’t work as different classNames will apply to different parts of the DOM.

So styled component doesn’t support this use case?

@probablyup

This comment has been minimized.

Show comment
Hide comment
@probablyup

probablyup Oct 9, 2018

Contributor

This is what I meant: https://codesandbox.io/s/r7x338zp5n, joining your custom className with the one that styled-components generates.

Contributor

probablyup commented Oct 9, 2018

This is what I meant: https://codesandbox.io/s/r7x338zp5n, joining your custom className with the one that styled-components generates.

@Albert-Gao

This comment has been minimized.

Show comment
Hide comment
@Albert-Gao

Albert-Gao Oct 9, 2018

Ah, I see! thanks!! :)

What about that MyPart belongs to a 3rd party lib where I can't access its code? Any way to pass the whole generated styled component class names (className+pClassName) to that MyPart with the help of .attrs()?

const MyPart = ({ className, pClassName }) => (
  <p className={classnames(className, pClassName)}>this is the P tag</p>
);

Albert-Gao commented Oct 9, 2018

Ah, I see! thanks!! :)

What about that MyPart belongs to a 3rd party lib where I can't access its code? Any way to pass the whole generated styled component class names (className+pClassName) to that MyPart with the help of .attrs()?

const MyPart = ({ className, pClassName }) => (
  <p className={classnames(className, pClassName)}>this is the P tag</p>
);
@probablyup

This comment has been minimized.

Show comment
Hide comment
@probablyup

probablyup Oct 9, 2018

Contributor

Updated the sandbox to illustrate: https://codesandbox.io/s/r7x338zp5n

If you do className in attrs, it'll be space-concatenated with the one styled-components generates. It's up to the third party library to accept className from outside though and put it on the child JSX.

Contributor

probablyup commented Oct 9, 2018

Updated the sandbox to illustrate: https://codesandbox.io/s/r7x338zp5n

If you do className in attrs, it'll be space-concatenated with the one styled-components generates. It's up to the third party library to accept className from outside though and put it on the child JSX.

@Albert-Gao

This comment has been minimized.

Show comment
Hide comment
@Albert-Gao

Albert-Gao Oct 9, 2018

I see. Thanks for your time.

Which means I still have to mix up css modules along with styled components... I just want to migrate all CSS usage to styled components. :D

Styled components sits in the middle, why can't we just generate a class name and pass it to the styled(MyPart) as a prop. Oh pass it first, then generate it later.

Albert-Gao commented Oct 9, 2018

I see. Thanks for your time.

Which means I still have to mix up css modules along with styled components... I just want to migrate all CSS usage to styled components. :D

Styled components sits in the middle, why can't we just generate a class name and pass it to the styled(MyPart) as a prop. Oh pass it first, then generate it later.

@probablyup

This comment has been minimized.

Show comment
Hide comment
@probablyup

probablyup Oct 9, 2018

Contributor

why can't we just generate a class name and pass it to the styled(MyPart) as a prop

You can. styled components accept the className prop just fine, it's up to the underlying component to do something with it

Contributor

probablyup commented Oct 9, 2018

why can't we just generate a class name and pass it to the styled(MyPart) as a prop

You can. styled components accept the className prop just fine, it's up to the underlying component to do something with it

@Albert-Gao

This comment has been minimized.

Show comment
Hide comment
@Albert-Gao

Albert-Gao Oct 9, 2018

So, if they require a different prop other than className for handling the styling. Then I still need to use the traditional css tech like classname lib or css modules.. :(

Albert-Gao commented Oct 9, 2018

So, if they require a different prop other than className for handling the styling. Then I still need to use the traditional css tech like classname lib or css modules.. :(

@probablyup

This comment has been minimized.

Show comment
Hide comment
@probablyup

probablyup Oct 9, 2018

Contributor

css modules still assigns to className, so you'd have the same issue

Contributor

probablyup commented Oct 9, 2018

css modules still assigns to className, so you'd have the same issue

@Albert-Gao

This comment has been minimized.

Show comment
Hide comment
@Albert-Gao

Albert-Gao Oct 9, 2018

The following code works without problem:

import DatePicker from 'react-datepicker'
import styles from './custom.css'

<DatePicker
  calendarClassName={styles.calendar}
/>

But if I change to this, it won't work:

const StyledDatePicker = styled(DatePicker)`
    .my-calendar {
        color: black;
    }
`;

<StyledDatePicker
   calendarClassName="my-calendar"
/>

Or this won't work either:

const StyledDatePicker = styled(DatePicker).attrs({
    calendarClassName: 'my-calendar'
})`
    .my-calendar {
        color: black;
    }
`;

<StyledDatePicker />

Albert-Gao commented Oct 9, 2018

The following code works without problem:

import DatePicker from 'react-datepicker'
import styles from './custom.css'

<DatePicker
  calendarClassName={styles.calendar}
/>

But if I change to this, it won't work:

const StyledDatePicker = styled(DatePicker)`
    .my-calendar {
        color: black;
    }
`;

<StyledDatePicker
   calendarClassName="my-calendar"
/>

Or this won't work either:

const StyledDatePicker = styled(DatePicker).attrs({
    calendarClassName: 'my-calendar'
})`
    .my-calendar {
        color: black;
    }
`;

<StyledDatePicker />
@probablyup

This comment has been minimized.

Show comment
Hide comment
@probablyup

probablyup Oct 9, 2018

Contributor

Oh I see. You could use something like recompose to rename the prop as needed: https://github.com/acdlite/recompose/blob/master/docs/API.md#renameprop

Contributor

probablyup commented Oct 9, 2018

Oh I see. You could use something like recompose to rename the prop as needed: https://github.com/acdlite/recompose/blob/master/docs/API.md#renameprop

@Albert-Gao

This comment has been minimized.

Show comment
Hide comment
@Albert-Gao

Albert-Gao Oct 10, 2018

Thanks, but that's tricky...
Because it uses className as a prop as well.

Which means, you need to use it like this:

<DatePicker
   className="my-date-picker"
   calendarClassName="my-calendar"
/>

I want to use styled components to cover them all rather than wrap the className and use traditional css class name for the calendarClassName prop.

Any way to do that?

:(

Albert-Gao commented Oct 10, 2018

Thanks, but that's tricky...
Because it uses className as a prop as well.

Which means, you need to use it like this:

<DatePicker
   className="my-date-picker"
   calendarClassName="my-calendar"
/>

I want to use styled components to cover them all rather than wrap the className and use traditional css class name for the calendarClassName prop.

Any way to do that?

:(

@joewood

This comment has been minimized.

Show comment
Hide comment
@joewood

joewood Oct 10, 2018

I'm not sure why your above example doesn't work:

const StyledDatePicker = styled(DatePicker)`
    .my-calendar {
        color: black;
    }
`;

<StyledDatePicker
   calendarClassName="my-calendar"
/>

The same approach works in this trivial example: https://codesandbox.io/s/q3zp4v70m9. You should be able to default the prop too, to make it simpler:

const StyledDatePicker = styled(DatePicker).attrs({
    calendarClassName:"my-calendar"
})`{
    color:blue;
   }
    .my-calendar {
        color: black;
    }`;

<StyledDatePicker/>

joewood commented Oct 10, 2018

I'm not sure why your above example doesn't work:

const StyledDatePicker = styled(DatePicker)`
    .my-calendar {
        color: black;
    }
`;

<StyledDatePicker
   calendarClassName="my-calendar"
/>

The same approach works in this trivial example: https://codesandbox.io/s/q3zp4v70m9. You should be able to default the prop too, to make it simpler:

const StyledDatePicker = styled(DatePicker).attrs({
    calendarClassName:"my-calendar"
})`{
    color:blue;
   }
    .my-calendar {
        color: black;
    }`;

<StyledDatePicker/>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment