How to change the height of a dropdown menu? - css

I'm hitting an API to get these data. I mapped the data to my select menu. I'm not able to change the height of the dropdown box . any idea on how it can be achieved?
react.js
inside render
<div className={styles.nationality}>
<label htmlFor="nationality">Nationality<span className={styles.star}>*</span></label><br/>
{/* <img className={styles.nationalitydrop} src={drop} alt='drop' /> */}
{['nationality'].map(key => (
<select
key={key}
className={styles.nationalitybox}
type="text"
placeholder="select"
menuPlacement="bottom"
onChange={(event) => this.handleUserInput(event)}
value={this.state.nationality}
name='nationality'
> {this.props.nationalityData.map(({[key]:id}) => <option className={styles.data}key={id}>{id}</option>)}
</select>
))}
</div>
stylesheet
.nationalitybox
{
width: 408px;
height: 56px;
background: #30333F 0% 0% no-repeat padding-box;
border-radius: 3px;
opacity: 1;
color: #B4B6C4;
font-size: 20px;
border-style:none none solid;
outline: none;
}
.nationalitybox:placeholder-shown{
font-size: 14px;
color: #B4B6C4;
}
.data{
background-color: #B4B6C4;
color: black;
width: 220px;
}
[![dropdown][1]][1]

I think you are using wrong to style your select menu, you cannot use 'style.nationalitybox' because that not a class.
I suggest you use these options.
1st Option:
Change className={styles.nationalitybox} To className = "nationalitybox".
2nd Option:
If you are using Material UI then you have to use useStyles above the component.
For example:
const useStyles = makeStyles((theme) => ({
nationalitybox: {
height: "56px"
}
}));
const ComponentName = () => {
const styles= useStyles();
}

Related

Google Places Auto Complete making input field go up

I am working with the react-places-autocomplete package.
Whenever I type text into the input field and get suggestions, it makes the whole input field jumps up, ruining the look.
How can I get the input field to stay in place and just have the suggestions drop down normally? I've tried adding a position: relative and top: Npx style to the suggestions, but that doesn't stop the input field from jumping up.
Searchbar.js
return (
<div className="search">
<PlacesAutocomplete
value={locationChars}
onSelect={handleSelect}
searchOptions={{ types: ["(cities)"] }}
onChange={handleChange}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div>
<input
ref={inputRef}
{...getInputProps({ placeholder: "Search Location" })}
className="search-input"
/>
<div className="suggestions-container">
{loading ? <div>Loading...</div> : null}
{suggestions.map((suggestion) => {
const style = {
backgroundColor: suggestion.active ? "#41b6e6" : "white",
};
return (
<div {...getSuggestionItemProps(suggestion, { style })}>
{suggestion.description}
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
<SearchIcon className="search-icon" />
</div>
Searchbar.css
.search {
display: flex;
flex: 1;
align-items: center;
border-radius: 24px;
background-color: purple;
margin-right: 1rem;
color: black;
opacity: 1 !important;
}
.search-input {
height: 12px;
padding: 10px;
border: none;
width: 100%;
}
.search-icon {
padding: 5px;
height: 22px !important;
background-color: blue;
}
.suggestions-container
}
Just a guess but you might want to do something with the suggestions-container class. I recently found react-google-autocomplete to be a very smooth experience btw. Happy Hacking!

Is it bad to use Refs to change styles in react?

here is a code example where i use Ref's to change style
import React, {useRef, useState, useEffect} from 'react'
import S from "./collapsible.module.css"
import PropTypes from 'prop-types'
import { faMinus, faPlus } from '#fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
function Collapsible(props) {
let myRef = useRef(null);
let buttonRef = useRef(null);
let [ button, setButton] = useState(true)
let Show = () => {
if(button) {
setButton(false)
buttonRef.current.style.backgroundColor = "#555"
myRef.current.style.maxHeight = myRef.current.scrollHeight + "px";
} else {
setButton(true)
buttonRef.current.style.backgroundColor = "hsl(181, 100%, 11%)"
myRef.current.style.maxHeight = "0px";
}
}
return (
<div
className={S.body}
>
<button
className={S.collapsible}
onClick={Show}
ref={buttonRef}
> {props.label}
<div className={S.icon}>
{button? <FontAwesomeIcon icon={faPlus} />:
<FontAwesomeIcon icon={faMinus} />}
</div>
</button>
<div
className={S.content}
ref={myRef}
>
<h3>{props.body}</h3>
</div>
</div>
)
}
Collapsible.propTypes = {
label: PropTypes.string,
body: PropTypes.string,
}
Collapsible.defaultProps = {
label: '',
body: "",
}
export default Collapsible
css:
.collapsible {
display: flex;
background-color: hsl(181, 100%, 11%);
color: white;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
outline: none;
font-size: 15px;
border-radius: 3px;
/* margin-bottom: 3px; */
box-shadow: 0px 1px 5px 1px black;
margin-top:13px;
}
.icon{
color:white;
position:absolute;
right:50px;
text-align:right;
justify-content: flex-end;
}
.active, .collapsible:hover {
background-color: #555;
}
.content {
padding: 0 18px;
max-height: 0px;
overflow: hidden;
transition: max-height 0.2s ease-out;
background-color: #f1f1f1;
}
This is just replicating this in React:
https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_collapsible_animate
I have read that using Refs is bad, especially when using it to change the DOM, but if I didn't change the style with the exact amount shown in "scrollHeight" then the transition would be a messed up speed.
If there is another method Is this still bad practice?
It's more common practice to use a state value to determine the style like this:
<button
className={S.collapsible}
onClick={Show}
style={{backgroundColor: button ? "#555" : "hsl(181, 100%, 11%)"}
>
{props.label}
<div className={S.icon}>
{button ? (
<FontAwesomeIcon icon={faPlus} />
) : (
<FontAwesomeIcon icon={faMinus} />
)}
</div>
</button>
Or have a conditional className for your styles:
<button
className={`${S.collapsible} ${
button ? S.buttonColor : S.anotherButtonColor
}`}
onClick={Show}
>
{props.label}
<div className={S.icon}>
{button ? (
<FontAwesomeIcon icon={faPlus} />
) : (
<FontAwesomeIcon icon={faMinus} />
)}
</div>
</button>
and add .buttonColor and .anotherButtonColor to your CSS Module file (collapsible.module.css).
.buttonColor {
background-color: #555;
}
.anotherButtonColor {
background-color: hsl(181, 100%, 11%);
}
For the maxHeight on myRef, I'd do something like:
<div className={S.content} ref={myRef}>
<div style={{ maxHeight: myRef.current.scrollHeight }}>
<h3>{props.body}</h3>
</div>
</div>

Autosize css dropdown to fit it's largest element

I would like to make a dropdown for choosing from a list of items that always have a width of it's widest element. The selected item is the item that's always shown and other options are shown on hover.
It's a simple CSS dropdown, and ideally, I would like to see pure CSS solution. Since I'm using React and this dropdown is a component, a js solution would be acceptable (without using jQuery or other libraries if possible).
const Dropdown = (props) => (
<div className="dropdown">
<div className="dropdown-item">{props.active}</div>
<div className="dropdown-body">
{props.items
.filter(x => x !== props.active)
.map(x => <div className="dropdown-item">{x}</div>)}
</div>
</div>
)
var items = [
"abc", "abcdcdssd", "a"
]
ReactDOM.render(
<div>Hello <Dropdown items={items} active={"abc"} /> world.</div>,
document.querySelector("#app")
)
.dropdown {
display: inline-block;
background-color: blue;
text-align: center;
}
.dropdown .dropdown-item {
background-color: red;
width: auto;
padding: 0 6px;
}
.dropdown .dropdown-body {
display: none;
position: absolute;
z-index: 1000;
}
.dropdown:hover .dropdown-body {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
In the example above, I would like for the "abc" element to have a width of the largest element "abcdcdssd".
Pure CSS Solution
A pure css solution would be to give your container a width: auto and use the visibility style instead of display on your items to hide them:
const Dropdown = (props) => (
<div className="dropdown">
<div className="dropdown-item">{props.active}</div>
<div className="dropdown-body">
{props.items
.filter(x => x !== props.active)
.map(x => <div className="dropdown-item">{x}</div>)}
</div>
</div>
)
var items = [
"abc", "abcdcdssd", "a"
]
ReactDOM.render(
<div>Hello <Dropdown items={items} active={"abc"} /> world.</div>,
document.querySelector("#app")
)
var items = [
"abc", "abcdcdssd", "a"
]
ReactDOM.render(
<div>Hello <Dropdown items={items} active={"abc"} /> world.</div>,
document.querySelector("#app")
)
.dropdown {
display: inline-block;
text-align: center;
vertical-align: top;
width: auto;
}
.dropdown .dropdown-item {
background-color: red;
padding: 0 6px;
}
.dropdown .dropdown-body {
visibility: hidden;
z-index: 1000;
}
.dropdown:hover .dropdown-body {
visibility: visible;
}
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="app"></div>
The caveat is that because the items are only hidden if you select the text your hidden items will be selected too.
JS Solution
You can measure the width of the dropdown body after the initial render and apply it to the active dropdown item. To make this work you initially need to use visibility: hidden instead of display: none because only the width of hidden elements can be measured. You could hide them as soon as they have been measured initially.
The example below uses react hooks which requires a version >16.8 but it can also be achieved with a class based component using componentDidMount.
const {useRef, useState, useLayoutEffect} = React;
const Dropdown = props => {
const bodyRef = useRef();
const [bodyWidth, setWidth] = useState(null);
const [itemsHidden, setItemsHidden] = useState(false);
useLayoutEffect(() => {
setWidth(bodyRef.current.clientWidth);
setItemsHidden(true);
}, []);
return (
<div style={{width: bodyWidth || 'auto'}} className="dropdown">
<div className="dropdown-item">{props.active}</div>
<div ref={bodyRef} className={`dropdown-body${itemsHidden ? ' hidden' : ''}`}>
{props.items
.filter(x => x !== props.active)
.map((x, idx) => (
<div key={idx} className="dropdown-item">{x}</div>
))}
</div>
</div>
);
};
var items = [
"abc", "abcdcdssd", "a"
]
ReactDOM.render(
<div>Hello <Dropdown items={items} active={"abc"} /> world.</div>,
document.querySelector("#app")
)
.dropdown {
display: inline-block;
background-color: blue;
text-align: center;
}
.dropdown .dropdown-item {
background-color: red;
width: auto;
padding: 0 6px;
}
.dropdown .dropdown-body {
position: absolute;
z-index: 1000;
}
.dropdown .dropdown-body.hidden {
display: none;
position: absolute;
z-index: 1000;
}
.dropdown:hover .dropdown-body {
display: block;
}
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="app"></div>

Change styles of parent on hover only if children not focused - Styled components

I have a div component:
const Parent = styled.div`
&:not(${Input}:focus):hover {
border-color: blue;
}
`;
and child which is input
const Input = styled.input``;
As you can see, I dont want to change border-color on Parent, if Input is focused. However atm the :hover doesnt work at all. Looking for help, thanks!
You can leverage :focus-within to do that.
div {
padding: 1em;
margin: 2em;
display: inline-block;
border-width: 3px;
border-style: solid;
}
div:hover {
border-color: red;
}
div,
div:focus-within,
div:focus-within:hover {
border: 3px solid blue;
}
<div>
<input type="text">
</div>
I don't know how you can handle it with only selector css, but you can trick it with javascript.
Your styled-component :
const Input = styled.input``
const Parent = styled.div`
border: 1px solid blue;
:hover {
border-color: ${p => p.inputFocus ? "blue" : "yellow"};
}
`
and in your render you can handle a state focus of you input.
render :
state = {
inputFocus: false
}
setFocus = () => this.setState({inputFocus: true})
unsetFocus = () => this.setState({inputFocus: false})
render() {
const { inputFocus } = this.state
return (
<Container inputFocus={inputFocus}>
<Input
onBlur={this.unsetFocus}
onFocus={this.setFocus}
/>
</Container>
)
}

Hide the dropdown list when clicking or scrolling on outside

I want to close my dropdown list after clicking or scrolling outside the pane. Still the dropdown box is open all time when we scrolling outside the dropdown box.. This is my code..
static defaultProps = { // <-- DEFAULT PROPS
wrapperStyle: {
display: 'inline',
},
menuStyle: {
borderRadius: '3px',
boxShadow: '0 2px 12px rgba(0, 0, 0, 0.1)',
padding: '2px 0',
fontSize: '90%',
position: 'fixed',
minWidth: '300px',
overflow: 'auto',
maxHeight: '250px',
display: 'inline',
}
}
..............................................................
<ReactAutocomplete
name="ReferredBy"
items = {patientsMasterData.ReferredBy && patientsMasterData.ReferredBy.map(referredObj =>(
{options:referredObj.RefName,
values:referredObj.RefID}
))
}
shouldItemRender={(item, value) => item.options.toLowerCase().indexOf(value.toLowerCase()) > -1}
getItemValue={(item) => item.options}
renderItem={(item, highlighted) =>
<div
key={item.values}
style={{ backgroundColor: highlighted ? '#3db4e5' : '#FFFFFF',cursor:'pointer', border:'1px solid lighten($grey-element,30%)',padding: '5px}}
{item.options}</div>}
inputProps={{placeholder:'Select...'}}
menuStyle={this.props.menuStyle}
wrapperStyle={this.props.wrapperStyle}
value={this.state.value}
onChange{e=>this.setState({value:e.target.value})}
onSelect={value => this.setState({ value })}
/>
& the css portion,
&_value1 {
flex:2;
white-space: normal;
width: 100%;
// overflow-y: auto;
font-size: 14px;
position: relative;
z-index: 2;
display: inline-block;
input, textarea {
width: 100%;
min-width: 200px;
height: 25px;
border: 1px solid $grey-element;
padding: 0 8px;
font-size: 12px;
}
&::after {
position: absolute;
right: 9px;
top: 10px;
content: '';
width: 0;
height: 0;
border-style: solid;
border-width: 6px 3px 0 3px;
border-color: $black transparent transparent transparent;
} }
How can I hide the dropdown box when scrolling outside?
In few words: you need to add event listener when dropdown is open and make ref on your dropdown to avoid click event on your dropdown, but fire it on clicking somewhere else (and remove eventlistener here). Also you can listen for scrolling events. This is implementation example:
import React, {Component} from 'react';
import { CSSTransition } from 'react-transition-group';
class Dropdown extends Component {
constructor(props) {
super(props);
this.setWrapperRef = this.setWrapperRef.bind(this);
this.handleClickOutside = this.handleClickOutside.bind(this);
};
setWrapperRef(node) {
this.wrapperRef = node;
};
handleClickOutside(e) {
e.stopPropagation();
if (this.wrapperRef && !this.wrapperRef.contains(e.target) && this.props.isOpen){
this.props.onClose();
}
};
componentDidUpdate(){
if(this.props.isOpen){
document.addEventListener('mousedown', this.handleClickOutside);
} else {
document.removeEventListener('mousedown', this.handleClickOutside);
}
}
render(){
return (
<div className={"dropdown " + (this.props.isOpen ? "show" : "hide")} ref={this.setWrapperRef}>
<CSSTransition in={this.props.isOpen} timeout={300} classNames="fadeIndown" unmountOnExit={true}>
{this.props.children}
</CSSTransition>
</div>
)
}
}
export default Dropdown;
const toggleDropdown = () => this.setState({ isDropdownOpen: !this.state.isDropdownOpen });
const closeDropdownThen = fn => (...params) => {
this.setState({ isDropdownOpen: false });
return fn(...params);
};
under the render you should define like that constant like above. And when you use
<Dropdown
isOpen={isDropdownOpen}
toggleDropdown={toggleDropdown}
className={s.dropDownContainer}
label="Export"
>
<DropdownItem onClick={closeDropdownThen(this.abcFunction)}>
CSV
</DropdownItem>
this is my dropDown component maybe it helps you. Best regards

Resources