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

Unable to style react-select component with styled-components v6 #4074

Open
dogfootruler-kr opened this issue Jul 5, 2023 · 17 comments
Open

Comments

@dogfootruler-kr
Copy link

Environment

## System:
 - OS: macOS 13.4.1
 - CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
 - Memory: 17.73 MB / 16.00 GB
 - Shell: 5.9 - /bin/zsh
## Binaries:
 - Node: 18.16.0 - ~/.nvm/versions/node/v18.16.0/bin/node
 - Yarn: 1.22.19 - ~/.yarn/bin/yarn
 - npm: 9.5.1 - ~/.nvm/versions/node/v18.16.0/bin/npm
 - Watchman: 2023.07.03.00 - /usr/local/bin/watchman
## npmPackages:
 - babel-plugin-styled-components: ^1.13.2 => 1.13.3
 - styled-components: ^6.0.2 => 6.0.2

Reproduction

https://codesandbox.io/s/styled-component-with-react-select-wsd87q

Steps to reproduce

Styling a components.ValueContainer from react-select is impossible as it expects a theme prop that is removed by styled-components.

Expected Behavior

Possible to style react-select

Actual Behavior

Impossible to style react-select

@pankajpatel
Copy link

I believe this is caused by the theme prop collision between SC and ReactSelect.

@dogfootruler-kr
Copy link
Author

That's correct @pankajpatel but is there any solution to this?

@CyrilQuandalle
Copy link

CyrilQuandalle commented Jul 12, 2023

Hello @dogfootruler-kr ,
Like my colleague @pankajpatel and you were saying there is indeed a prop collision conflict. Having the same issue, and after making some thinking on it I managed to found a solution :

export const DropdownBaseOption: FC<OptionProps<any>> = (props) => {
  const { OptionComponent } = props.selectProps;
  const { theme, ...otherProps } = props;
  return (
    <BaseOptionContainer selectTheme={theme} {...otherProps}>
      {OptionComponent ? <OptionComponent {...props} /> : <div>{props.children} </div>}
    </BaseOptionContainer>
  );
};

const BaseOptionContainer = styled(components.Option).attrs<{ selectTheme: Theme }>((props) => ({
  theme: props.selectTheme,
}))<{ selectTheme: Theme }>``;

that way the react-select theme is passed to react-select via styled-component and not used by it

@dogfootruler-kr dogfootruler-kr changed the title Impossible to style react-select component with styled-components Unable to style react-select component with styled-components Jul 13, 2023
@dogfootruler-kr
Copy link
Author

Hello @CyrilQuandalle and thank you for your example but sadly I still have an error when opening the select.

I made a new sandbox with your code change:
https://codesandbox.io/s/condescending-lamport-ksjk3r?file=/src/App.tsx

Do you use a different react-select version maybe?

@CyrilQuandalle
Copy link

Hello @dogfootruler-kr ,
No I use the same react-select as you but I still use styled-components version 5. I tried version 6 and indeed my workaround doesn't work anymore, we're investigating on that at the moment among other issues we have with this new version.

@dogfootruler-kr dogfootruler-kr changed the title Unable to style react-select component with styled-components Unable to style react-select component with styled-components v6 Jul 14, 2023
@dogfootruler-kr
Copy link
Author

I'm sorry I completely forgot to mention I was using styled-components v6.

@CyrilQuandalle
Copy link

It's ok, it's actually on me because I didn't read that you were using SC version 6 in the description of your issue

@birmitt
Copy link

birmitt commented Oct 26, 2023

Do we know why the "theme" prop is being removed by the styled-components wrapper since v6?

When I revert that single change, as done in the PR #4129, both styled-componets@6.1.0 and react-select@5.7.7 are working together perfectly.

@espenh
Copy link

espenh commented Nov 16, 2023

Here's a simple sandbox to show the issue: https://codesandbox.io/p/sandbox/eloquent-morning-gv6p4k.

As a workaround specifically for react-select with default themes, it is possible to import import { defaultTheme } from 'react-select', and then pass that property manually, but it's not ideal.

@birmitt
Copy link

birmitt commented Nov 16, 2023

A solution to recover the eaten theme prop with the defaultTheme could look like this:

import {components, defaultTheme, SingleValueProps} from "react-select";

function Inner(props: SingleValueProps) {
    return (
        <components.SingleValue theme={defaultTheme} {...props}>
            {props.children}
        </components.SingleValue>
    )
}

const SingleValue = styled(Inner)`
    // custom styling…
`;

export default SingleValue;

As I do all styling with styled-components, I don't dependent on the integrated styling mechanism of react-select.
That's why this solution works great for me.

@Dron007
Copy link

Dron007 commented Dec 22, 2023

Any chances to see a fix in styled-components? We have about 6-8 components based on react-select and each has about 4-6 custom inner react-select components. I don't think it is a good idea to add some hack to all these places. I would prefer to see a global change or better update styled-components so it doesn't break react-select.

quantizor added a commit that referenced this issue Dec 27, 2023
Fixed the specific scenario documented in #4074.
quantizor added a commit that referenced this issue Dec 27, 2023
Fixed the specific scenario documented in #4074.
quantizor added a commit that referenced this issue Dec 27, 2023
Fixed the specific scenario documented in #4074.
@quantizor
Copy link
Contributor

This issue is fixed in 6.1.4 when using attrs to provide an alternate theme prop https://codesandbox.io/p/sandbox/styled-component-with-react-select-forked-m62nj4?file=%2Fexample.js%3A7%2C18

I don't think we can let theme through as a normal prop without a breaking change since styled-components currently considers normal theme prop as an actual styled-components theme and not something like react-select is expecting.

@Dron007
Copy link

Dron007 commented Dec 27, 2023

@quantizor What is the right way to fix it in this code?

import React from "react";
import Select from "react-select";
import styled from "styled-components";
import { components } from "react-select";

const optionsArray = [
  { value: "o1", label: "option 1" },
  { value: "o2", label: "option 2" },
];

const StyledControl = styled(components.Control)`
  border: 1px solid red;
`;

const SelectControl = (props) => {
  console.log("props.theme", props.theme);
  return <StyledControl {...props} />;
};

export default () => (
  <Select
    components={{ Control: SelectControl }}
    value={[{ value: "o1", label: "option 1" }]}
    options={optionsArray}
  />
);

Sandbox: https://codesandbox.io/p/sandbox/codesandboxer-example-forked-l7s2ny?file=%2Fexample.tsx%3A18%2C6

As you can see, we don't use theme neither for styled component nor for react-select sub-component but react-select still expect that this prop is passed among others. We have many places like this and I don't think it would be correct to pass theme prop everywhere just to workaround the case when styled components deletes theme prop. Could we find a better solution? I still don't quite understand what was changed in v6 that break the logic that worked perfectly in v5. It is not mentioned in Changelist.

If the problem is in name collision maybe it could be solved by adding some global parameter with the alternative name for the theme prop. It would not break current logic with theme prop by default but in case of name collisions one could change it to custom name like styledTheme. It still would look weird when themes are not used but at least it would be one place not 20 different places to change.

@quantizor
Copy link
Contributor

I provided the setup in the forked sandbox I linked in my comment. You need to provide the theme as a different prop and then alias it inside attrs

@Dron007
Copy link

Dron007 commented Dec 27, 2023

@quantizor But in my case I don't use theme functionality at all. Should I add it just to workaround this case, do it in many places and keep it in mind adding any new select sub-components? Maybe there is a better solution? Can we do it globally somehow?

@quantizor
Copy link
Contributor

I think ultimately the right fix is to deprecate passing a styled-components theme over props and use $theme instead. Then theme can just be a normal prop.

@Dron007
Copy link

Dron007 commented Dec 27, 2023

I think ultimately the right fix is to deprecate passing a styled-components theme over props and use $theme instead. Then theme can just be a normal prop.

@quantizor That would be better too especially now when all props without '$' prefix are passed to original component. I had to restore original logic using isPropValid from @emotion. Can I somehow use shouldForwardProp from StyleSheetManager to pass theme prop to the wrapped component too?

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