xqcccccccccc
xqcccccccccc

Reputation: 93

How to style nested option based on condition in react-select?

I have nested options for my <Select /> component and i basically want to remove some styles if the option is selected, there is documentation for normal options but can't find a way to do it for nested ones. Here is what my component looks like:


<Select
  id="custom"
  name="custom"
  options={_.chain(customOptions)
    .map(op1 => ({
      label: (
        <div
          className="flex items-center justify-between text-sm font-semibold"
        >
          <span>
            {op1.title}
          </span>
        </div>
      ),
      options: _.map(op1.tags, tag => ({
        label: (
          <div
            className="mx-2 flex items-center justify-between"
          >
            <span className="font-semibold indent-2">
              {tag}
            </span>
          </div>
        ),

        value: tag,
        group: op1,
      })),
    }))
    .value()}
  placeholder="Select Option"
  menuPortalTarget={document.body}
  type="default"
  styles={{
    menuPortal: (base: any) => ({ ...base, zIndex: 9999 }),
  }}
/>

What is want is to remove font-semibold indent-2 classes from <span>{tag}</span> for selected tag, is there any way to do this?

Upvotes: 1

Views: 2047

Answers (1)

davidx1
davidx1

Reputation: 3673

Styling nested options is no different to styling none nested options. The issue with your approach is that you are passing your markdown and style all into the options prop.

Here are the two 'correct' way of using the library:

1) [Recommended] Styling through 'style' prop

Pass in your raw data into the options prop. Pass the styles into the styles prop as objects.

const customOptions = [
  { groupLabel: "number", items: ["1", "2", "3"] },
  { groupLabel: "words", items: ["one", "two", "three"] }
];

const options = customOptions.map((op1) => ({
  label: op1.groupLabel,
  options: _.map(op1.items, (item) => ({
    label: item,
    value: item
  }))
}));

const customStyles = {
  option: (provided: any, state: { isSelected: any }) => ({
    ...provided,
    borderBottom: "1px dotted pink",
    color: state.isSelected ? "red" : "blue",
    backgroundColor: state.isSelected ? "grey" : "inherit"
  })
};

const App = () => <Select options={options} styles={customStyles} />;

2) Styling through 'components' prop

If you really want to change the markup then you can do this; Pass in the raw data into the options prop as before. Pass in markup and style through the components prop to override the built in components.

import React from "react";
import Select, { OptionProps, GroupHeadingProps } from "react-select";
import _ from "lodash";

const customOptions = [
  { groupLabel: "number", items: ["1", "2", "3"] },
  { groupLabel: "words", items: ["one", "two", "three"] }
];

const options = customOptions.map((op1) => ({
  label: op1.groupLabel,
  options: _.map(op1.items, (item) => ({
    label: item,
    value: item
  }))
}));

const Option = ({ innerProps, children, isSelected }: OptionProps<{}>) => {
  return (
    <div
      {...innerProps}
      style={{ backgroundColor: isSelected ? "red" : "white" }}
    >
      {children}
    </div>
  );
};

const GroupHeading = ({ children }: GroupHeadingProps<{}>) => {
  return <div style={{ backgroundColor: "pink" }}>{children}</div>;
};

const App = () => (
  <Select options={options} components={{ Option, GroupHeading }} />
);

export default App;

I STRONGLY recommend you go with option 1 - styling through the style prop. With option 2, you will need to do a lot more work. You basically lose all the things that comes out the box and have to implement your own markup, styling, and accessibility features. It's really only useful for people with really complicated UI, which doesn't seem to be the case for you.

Upvotes: 2

Related Questions