I'm working with react-select and I want to customize only one option from the drop-down. Is there such an opportunity? I would like to do something like:
const CustomOption = ({ innerRef, innerProps, data }) => data.custom
? (<div ref={innerRef} {...innerProps} >I'm a custom link</div>)
: defaultOne //<--- here I would like to keep default option
<ReactSelect
components={{ Option: CustomOption }}
options={[
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
{ custom: true },
]}
/>
Any thoughts how to achive that?
Your feeling is good, you can achieve your goal with the following way:
const CustomOption = props => {
const { data, innerRef, innerProps } = props;
return data.custom ? (
<div ref={innerRef} {...innerProps}>
I'm a custom link
</div>
) : (
<components.Option {...props} />
);
};
const options = [
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" },
{ custom: true }
];
function App() {
return <Select components={{ Option: CustomOption }} options={options} />;
}
The important thing to notice is to pass the entire props property to the components.Option to have the default behaviour.
Here a live example.
Related
I just start learning Reactjs and I have trouble with Component. Here are my code:
export default function ChonLanguage() {
const [selectedOption, setSelectedOption] = useState([]);
const options = [
{ value: 'Vietnamese', label: 'Vietnamese' },
{ value: 'English', label: 'English' },
{ value: 'Chinese', label: 'Chinese' },
{ value: 'Japanese', label: 'Japanese' },
{ value: 'German', label: 'German' },
];
const handleChangeOption = () => {
return setSelectedOption;
}
return (
<Select className={`col-12 o-languages`}
onChange={handleChangeOption()}
options={options} />
)
}
It shown my options, but when I submit, I not save into Database. What should I change? Thanks
Made some minor changes to your code.
Kindly note:-
setSelectedOption is function of type React.dispatch<[]> which will update selectedOption state value so you need to pass some value in that.
useEffect is used to check the updated value of selectedOption, you may not use it.
export default function ChonLanguage() {
const [selectedOption, setSelectedOption] = useState([]);
const options = [
{ value: "Vietnamese", label: "Vietnamese" },
{ value: "English", label: "English" },
{ value: "Chinese", label: "Chinese" },
{ value: "Japanese", label: "Japanese" },
{ value: "German", label: "German" }
];
const handleChangeOption = (event) => {
return setSelectedOption(event.value);
};
useEffect(() => {
console.log(selectedOption);
}, [selectedOption]);
return (
<Select
className={`col-12 o-languages`}
onChange={(e) => {
handleChangeOption(e);
}}
options={options}
/>
);
}
I have some trouble with my react-select: When I click 'Submit', it save an object that have both 'value' and 'label' like this:
enter image description here
All I need is when I choose, it's show label list, and when I submit, it save only value. What can I do? Here are my code:
const [mainLang, setMainLang] = useState("");
const mainLangOptions = [
{ value: 'vi', label: 'Vietnamese' },
{ value: 'en', label: 'English' },
{ value: 'zh', label: 'Chinese' },
{ value: 'ja', label: 'Japanese' },
{ value: 'de', label: 'German' },
];
//This is Select part
<Select
onChange={(e) =>setMainLang(e)}
options={mainLangOptions}
/>
You need to set the option value as the mainLangOptions.value and the label as
mainLangOptions.label. By doing that you will display the label as option labels and save the value as the value of option tag. Check out the code below :
import React from "react";
import "./styles.css";
class App extends React.Component {
constructor() {
super();
this.state = {
mainLanguage: ""
};
}
onOptionChangeHandler = (event) => {
this.state.mainLanguage = event.target.value;
console.log(this.state.mainLanguage);
};
render() {
const mainLangOptions = [
{ value: "vi", label: "Vietnamese" },
{ value: "en", label: "English" },
{ value: "zh", label: "Chinese" },
{ value: "ja", label: "Japanese" },
{ value: "de", label: "German" }
];
return (
<div>
<select onChange={this.onOptionChangeHandler}>
<option>Please choose one option</option>
{mainLangOptions.map((option, index) => {
return (
<option value={option.value} key={index}>
{option.label}
</option>
);
})}
</select>
</div>
);
}
}
export default App;
You must use e.target.value inside your setMainLang
<Select onChange={(e) => setMainLang(e.target.value)}>
This should work for your code but if it doesn't work, here is a complete code that I have tested in code sandbox and you can try it.
import React, { useState } from "react";
import { Select } from "#chakra-ui/react";
const Users = () => {
const [mainLang, setMainLang] = useState("");
const mainLangOptions = [
{ value: "vi", label: "Vietnamese" },
{ value: "en", label: "English" },
{ value: "zh", label: "Chinese" },
{ value: "ja", label: "Japanese" },
{ value: "de", label: "German" }
];
return (
<>
<Select onChange={(e) => setMainLang(e.target.value)}>
{mainLangOptions.map((op) => (
<option value={op.value}>{op.label}</option>
))}
</Select>
<h1>{mainLang}</h1>
</>
);
};
export default Users;
I am using react-select in my project. I have it for multiple select and it looks like this:
and it works fine. The problem is I would like to have one option already selected and it would be not clearable so it will not have "X" near it
I just need it for one option, all others have to be normally in the options and clearable.
How can I achieve that? Is it a special prop added to options or can I check them some way that if option name is commercial it will not have possibility to clear and would be selected on initial
react-select has a fixed options example on the docs but I found this solution is much cleaner. You can remove MultiValueRemove component (the delete button) based on the option value:
const MultiValueRemove = (props) => {
if (props.data.isFixed) {
return null;
}
return <components.MultiValueRemove {...props} />;
};
export default () => {
return (
<Select
isMulti
defaultValue={[colourOptions[0], colourOptions[1]]}
isClearable={false}
options={colourOptions}
components={{ MultiValueRemove }}
/>
);
};
The select above will remove the delete button of any option that has the isFixed property set to true (the first 2 options below).
export const colourOptions = [
{ value: 'ocean', label: 'Ocean', color: '#00B8D9', isFixed: true },
{ value: 'red', label: 'Red', color: '#FF5630', isFixed: true },
{ value: 'purple', label: 'Purple', color: '#5243AA' },
{ value: 'orange', label: 'Orange', color: '#FF8B00' },
{ value: 'yellow', label: 'Yellow', color: '#FFC400' },
{ value: 'green', label: 'Green', color: '#36B37E' },
{ value: 'forest', label: 'Forest', color: '#00875A' },
{ value: 'slate', label: 'Slate', color: '#253858' },
{ value: 'silver', label: 'Silver', color: '#666666' },
];
Live Demo
You can remove that by using isClearable props of react-select like below
Consider your options array have fixed boolean set to true
<Select
// other props
isClearable={options.some(v => !v.isFixed)}
/>
And you can change you multiValueRemove in styles const like this
const styles = {
// other styles here
multiValueRemove: (base, state) => {
return state.data.isFixed ? { ...base, display: 'none' } : base;
},
};
You can find more info in Fixed option section of https://react-select.com/home#fixed-options
Try this:
export const CreatingSelect: FC<CreatingSelectProps> = (props) => {
const { className, components, ...restProps } = props;
const selectClassName = cn('select', className);
const MultiValueRemove = (props: PropsWithChildren<any>) => {
return (
<div className={props.innerProps.className} onClick={props.innerProps.onClick}>
<SvgIcon name={iconNames.cross} />
</div>
);
};
return (
<SelectStyled
styles={customStyles}
className={selectClassName}
classNamePrefix='select'
components={{ ...components, MultiValueRemove }}
{...restProps}
/>
);
};
I am using react-select with the isMulti attribute on a form. For simplicity the data are the following
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
]
if i select the first two options and then i submit the form, the react-select field will have the following value
reactSelectField: [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' }
]
how can i set the fieldValue to
reactSelectField: ['chocolate', 'strawberry']
which is actually the values of the options and not the whole object?
You could transform values yourself using onChange and a form state
const [values, setValues] = React.useState([]);
<Select
options={options}
value={values.map((value) => ({
label: value,
value,
})}
onChange={(values) => {
setValues(values.map((option) => option.value));
}}
/>
Or create your own wrapper to return the value in the format you expect
const MyMultiSelect = ({ values = [], options = [], onChange, ...props }) => (
<Select
{...props}
value={values.map((value) => ({
label: value,
value,
})}
options={options.map((value) => ({
label: value,
value,
})}
onChange={(values) => {
onChange(values.map((option) => option.value));
}}
/>
)
// Usage
<MyMultiSelect
options={["chocolate", "strawberry", "banana"]}
values={["chocolate", "banana"]}
onChange={(values) => {
console.log(values); // ["chocolate", "banana"]
}}
/>
So, I am building an avatar creator for my application, and I have a Carousel that holds multiple RadioGroups, I can slide to the new radiogroup, but when I click on any of the other radio groups (except for the first one) and it will only target the value from the first one.
<Carousel options={{ fullWidth: true, indicators: true }} className="black-text center">
<div>
<RadioGroup
name="hair"
label="Hair Selection"
value={this.state.avatar.topType}
onChange={this.handleAvatarChange}
options={[{ label: 'Eyepatch', value: 'Eyepatch' }, { label: 'Long
Hair', value: 'LongHairStraight2' }, { label: 'Medium Hair', value:
'LongHairNotTooLong' }, { label: 'Short Hair', value:
'ShortHairShortFlat' }, { label: 'Short Dreads', value:
'ShortHairDreads01' }, { label: 'Balding', value: 'ShortHairSides'
}]}
/>
</div>
<div>
<RadioGroup
name="hairColor"
label="Hair Selection"
value={this.state.avatar.hairColor}
onChange={this.handleAvatarChange}
options={[{ label: 'Brown', value: 'Brown' }, { label: 'Blonde',
value: 'Blonde' }, { label: 'Red', value:
'Red' }, { label: 'Gray', value:
'Gray' }, { label: 'Black', value:
'Black' }, { label: 'Auburn', value: 'Auburn'
}]}
/>
</div>
</Carousel>
handleAvatarChange = (event) => {
let selection = event.target.value;
let type = event.target.name;
console.log(selection, 'event')
console.log(type, 'type');
let avatarCopy = { ...this.state.avatar };
if (type === 'hair') {
avatarCopy.topType = selection
this.setState({ avatar: avatarCopy });
} else if (type === 'hairColor') {
avatarCopy.hairColor = selection;
this.setState({ avatar: avatarCopy });
}
}
I expect that when I slide to the next slide on the carousel, that I can change the state based on the type that was passed back to my handleAvatarChange function. Instead, all of the slides are changing the values based on the first slide.
It seems like the autogenerated id numbering for the options resets to 0 for each radiogroup, even if they are in the same DOM.
Therefore, each n input of the radio groups has the same id (<input id="radio0" type="radio" value="1" checked="">).
I have reported the bug here.
As a workaround, I'm requesting an "id" prop, and if not found, concatenating the component's name to the index to build the id's.
var RadioGroup = function RadioGroup(_ref) {
var onChange = _ref.onChange,
withGap = _ref.withGap,
disabled = _ref.disabled,
name = _ref.name,
radioClassNames = _ref.radioClassNames,
value = _ref.value,
options = _ref.options;
return _react.default.createElement(_react.default.Fragment, null, options.map(function (radioItem, idx) {
return _react.default.createElement("label", {
className: radioClassNames,
htmlFor: radioItem.id ? radioItem.id : "radio".concat(radioItem.name).concat(idx),
key: radioItem.id ? radioItem.id : "radio".concat(radioItem.name).concat(idx)
}, _react.default.createElement("input", {
id: radioItem.id ? radioItem.id : "radio".concat(radioItem.name).concat(idx),
value: radioItem.value,
type: "radio",
checked: radioItem.value === value,
name: name,
onChange: onChange,
disabled: disabled,
className: (0, _classnames.default)({
'with-gap': withGap
})
}), _react.default.createElement("span", null, radioItem.label));
}));
};