Autoclose bootstrap 5 Dropdown without toggle in React - reactjs

I have a search field that shows data as dropdown.item when user is typing. The library is React Bootstrap (bootstrap 5). This is working great. The dropdown is showing. The problem is that the dropdown persist when clicking outside or navigating to a new link. The dropdown is in a header that does not get rerendered with the rest of the page. Using NextJS. Any tips on how to close a dropdown that has no toggle?
<form className="d-none d-sm-inline-block" style={{ zIndex: "1000" }}>
<div className="input-group input-group-navbar">
<input
type="text"
className="form-control"
placeholder="Søk"
aria-label="Search"
onChange={(event) => {
setSearchTerm(event.target.value);
}}
/>
<button className="btn" type="button">
<Icon.Search className="align-middle" />
</button>
</div>
{searchData.length >= 1 && (
<Dropdown style={{ position: "absolute", background: "white" }} autoClose="outside">
{searchData.slice(0, 10).map((element, index) => {
return (
<Link key={element.agressoResourceId} href={`employees/69918`} passHref replace={true}>
<Dropdown.Item>
{element.firstname} - {element.lastname}
</Dropdown.Item>
</Link>
);
})}
</Dropdown>
)}
</form>

The solution was to use onBlur event and hide the dropdown. The problem comes with the onblure is triggered before you press the item. The solution here was to use a setTimeout of 200ms.

Related

Field Array in React using formik

I wanted to follow like a todo list. Something just like in the picture below.
Right now, the problem with my code is that, its working differently.
I wanted only one input that renders a list of divs instead of input fields.
Exactly just like in the picture below:
Pls check my codesandbox here
CLICK HERE
<FieldArray
name="todos"
render={(arrayHelpers) => (
<div>
{formik.values.todos.map((friend, index) => (
<div key={index} style={{ display: "flex", gap: "1rem" }}>
<input
name={`todos[${index}].name`}
value={formik.values.todos[index].name}
onChange={formik.handleChange}
/>
<button
disabled={formik.values.todos?.length === 1}
type="button"
onClick={() => arrayHelpers.remove(index)}
className="deleteButton"
>
Remove
</button>
</div>
))}
<button
type="button"
onClick={() => arrayHelpers.push({ name: "" })}
>
Add
</button>
</div>
)}
/>
Here is a very simple and rude approach - I used Formik my project some time ago and I'm pretty sure it's not perfect but this is exactly what you need.
So some details.
do not render input for every item in your list, you need only render it's value and element with delete handler
you need only one controlled input and it's value is used for name field in your todos. State is cleaned when you click Add button.
you need to render your element only if formik.values.todos.lenght > 0
you need to disable Delete button when formik.values.todos.lenght === 1
Add button should be disabled when newValue.lenght === 0
Piece a cake, right?

React Hook Form reset Controller (value) to default

Here is an example of my component, wrapped into Controller
<div className="mt-1">
<Controller
control={control}
name="selectedBirthMonth"
defaultValue={selectedMonth}
render={({ field }) => (
< SelectBirthMonth
field={field}
startYear={startYear}
selectedYear={selectedYear}
months={months}
value={selectedMonth}
reducedMonths={reducedMonths}
onChange={useEffect(() => monthSelect(field.value)), [selectedMonth]}/>
)}
/>
</div>
For now I am just trying to reset it with a button. Later I'd love to conditionally reset, depending on the value in a sibling component. Would be great to get it work with the button in the first place:
<input
style={{ display: "block", marginTop: 20 }}
type="button"
onClick={() =>
reset(selectedBirthMonth)
}
value="Reset with values"
/>
I get en error: selectedBirthMonth is not defined. Bassicaly, what I am aming for,on click, the whole component goes to default / a state it had when first rendered. What am I missing?
reset didn't do the job somehow, but setValue did. However I am setting to a value, not to the original state after first render, but in my case it's same.
<input
style={{ display: "block", marginTop: 20 }}
type="button"
onClick={() =>
etValue('selectedBirthMonth', lastAvaliableMonth)
}
value="Reset with values"
/>

CSSTransition not working with stripe elements React

I have a CSSTransition that works until I add the CardElement from "#stripe/react-stripe-js";
<CSSTransition
classNames="method"
in={radio === 'add-card'}
exit={!(radio === 'add-card')}
timeout={500}
unmountOnExit>
<form id="payment-form" onSubmit={handleSubmit} className="stripe-ad">
<input
type="text"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter Email Address (Optional)"
/>
<CardElement id="card-element" options={cardStyle} onChange={handleChange} />
{error && (
<div className="card-error" role="alert">
{error}
</div>
)}
<p className={succeeded ? "result-message" : "result-message hidden"}>
Payment succeeded, see the result in your
<a
href={`https://dashboard.stripe.com/test/payments`}
>
{" "}
Stripe dashboard.
</a> Refresh the page to pay again.
</p>
</form>
</CSSTransition>
When I comment out the , the transition will work properly over the 500ms time interval. When I leave the Card element in, it will refuse to adhere to the transition rules.
I'm using the base cardstyle
const cardStyle = {
style: {
base: {
color: "#32325d",
fontFamily: 'Arial, sans-serif',
fontSmoothing: "antialiased",
fontSize: "16px",
"::placeholder": {
color: "#32325d"
}
},
invalid: {
color: "#fa755a",
iconColor: "#fa755a"
}
}
};
The problem is that the CardElement either has its own transition on mount, or the style needs to be changed. Has anyone ever had this issue with the stripe element on transition?
I suspect that this will not work as the Elements exist within a Stripe-hosted iframe. Only certain styles are supported on Elements:
https://stripe.com/docs/js/appendix/style
I suggest opening an issue on github with a minimal example of this, for example forked from the codesandbox demo.
https://github.com/stripe/react-stripe-js/issues

Is the z-index incorrect for these radio toggles behind the Semantic-UI-React Loading component?

I'm working on a form that has Semantic-UI Radio toggles, and the loader and the toggle's appear to be loading in the wrong z-index.
I checked the css and the toggle contains the following
.ui.toggle.checkbox label:after {
z-index: 2;
}
while the loader is
.ui.dimmer {
z-index: 1000;
}
which seems like the appropriate behaviour. I want the toggles to be behind the loader to present the best user experience. Can anyone tell me if the current behaviour is by design or not? Trying to determine if this is a bug to be reported or a feature to be requested or if there's a problem with my implementation.
My code (edited for brevity)
import { Form, Dropdown, DropdownItemProps, Dimmer, Loader, Button, Icon, Segment } from "semantic-ui-react";
return (
<Fragment>
<div style={{ display: "flex", flexDirection: "column" }}>
<div className="ui segments">
<PageHeader
text="Some text"
subText="Some subtext"
pageIcon="cogs icon"
/>
</div>
<Dimmer.Dimmable dimmed={loading}>
<Dimmer simple active={loading}>
<Loader>Loading</Loader>{" "}
</Dimmer>
<Form onSubmit={() => save()}>
<Form.Checkbox
label="Label 1"
checked={display}
onChange={(e, { checked }) => setDisplay(!!checked)}
toggle
/>
<Form.Input
label="Label 2"
placeholder="Placeholder"
value={data}
onChange={(e, { value }) => setData(value)}
/>
</Form.Group>
</Form>
</Dimmer.Dimmable>
</div>
</Fragment>
);
The comment helped me out. The problem was resolved using https://coder-coder.com/z-index-isnt-working/#alternative-solution-remove-positioning-from-the-content-so-it-wont-limit-the-modals-z-index from the suggestion.
I used a sticky position for the form element. Not necessarily the best solution but it sufficed for this purpose.

Influence tab order of Material UI controls

I have an app built up with React and Material UI. Within one view it is possible to have several text fields and several buttons. Now, when I have the focus on one text field and then press Tab I cannot reliably anticipate which one of the controls will be the next one to get the focus. I want to first tab through all the text fields and then secondly tab through all the buttons.
<DialogContent>
<DialogContentText>
The username and password that were used are incorrect. Please provide the correct credentials in order to login to the API.
<Stepper activeStep={this.state.credentialsStep} orientation='vertical'>
{
this.steps.map((label, index) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
<StepContent>
<Typography>{this.stepContent[index]}</Typography>
{this.stepAction[index]}
<Grid container direction='row' className='m-t-26'>
<Button color='primary'
onClick={() => {
this.state.credentialsStep === 0 ? this.onClickCancel() : this.onClickBack();
}}>
{this.state.credentialsStep === 0 ? 'Cancel' : 'Back'}
</Button>
<Button variant='contained'
color='primary'
onClick={() => {
this.state.credentialsStep === this.steps.length - 1 ? this.onClickLogin() : this.onClickNext();
}}>
{this.state.credentialsStep === this.steps.length - 1 ? 'Login' : 'Next'}
</Button>
</Grid>
</StepContent>
</Step>
))
}
</Stepper>
</DialogContentText>
</DialogContent>
Is there a way to set the tab order of controls?
You can control this with the tabIndex property, but you may be better off to figure out how to have the elements appear in the source in the order you would want the focus to go.
I have found this resource handy: https://bitsofco.de/how-and-when-to-use-the-tabindex-attribute/
When to use a positive tabindex value
There is almost no reason to
ever use a positive value to tabindex, and it is actually considered
an anti-pattern. If you’re finding the need to use this value to
change the order in which elements become focusable, it is likely that
what you actually need to do is change the source order of the HTML
elements.
One of the problems with explicitly controlling tabindex order is that any elements with a positive value are going to come before any other focusable elements that you haven't explicitly put a tabindex on. This means that you could end up with very confusing focus order if you miss any elements that you would want in the mix.
If you want to have the button on the right come before the button on the left in the focus order, there are various CSS options that would allow the button on the right to come first in the source order.
If, however, you decide that explicitly specifying the tabindex is your best option, here is an example showing how to do this for TextField and Button:
import React from "react";
import ReactDOM from "react-dom";
import TextField from "#material-ui/core/TextField";
import Button from "#material-ui/core/Button";
function App() {
return (
<div className="App">
<TextField label="1" inputProps={{ tabIndex: "1" }} />
<br />
<TextField label="3" inputProps={{ tabIndex: "3" }} />
<br />
<TextField label="2" inputProps={{ tabIndex: "2" }} />
<br />
<Button tabIndex="5">Button 5</Button>
<Button tabIndex="4">Button 4</Button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
You may want to use the html attribute tabindex. This allows you to specify the order that tabbing will go through in your form. You can read more about it here and I've put a small example below, setting the tab index of your button to #1
<StepContent>
<Typography>{this.stepContent[index]}</Typography>
{this.stepAction[index]}
<Grid container direction="row" className="m-t-26">
<Button
tabIndex="1" // This will make the button the first tab index for the form.
color="primary"
onClick={() => {
this.state.credentialsStep === 0
? this.onClickCancel()
: this.onClickBack();
}}
>
{this.state.credentialsStep === 0 ? "Cancel" : "Back"}
</Button>
<Button
variant="contained"
color="primary"
onClick={() => {
this.state.credentialsStep === this.steps.length - 1
? this.onClickLogin()
: this.onClickNext();
}}
>
{this.state.credentialsStep === this.steps.length - 1 ? "Login" : "Next"}
</Button>
</Grid>
</StepContent>;
You can use a css trick to render the buttons in reverse order, but with css to reverse the buttons in UI.
<DialogContent>
<DialogContentText>
The username and password that were used are incorrect. Please provide the correct credentials in order to login to the API.
<Stepper activeStep={this.state.credentialsStep} orientation='vertical'>
{
this.steps.map((label, index) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
<StepContent>
<Typography>{this.stepContent[index]}</Typography>
{this.stepAction[index]}
<Grid container direction='row' className='m-t-26'>
// Box wrapper added <Box style={{ display: 'flex', flexDirection: 'row-reverse', justifyContent: 'flex-end' }}>
// First Button is now "Next in JSX <Button variant='contained'
color='primary'
onClick={() => {
this.state.credentialsStep === this.steps.length - 1 ? this.onClickLogin() : this.onClickNext();
}}>
{this.state.credentialsStep === this.steps.length - 1 ? 'Login' : 'Next'}
</Button>
<Button color='primary'
onClick={() => {
this.state.credentialsStep === 0 ? this.onClickCancel() : this.onClickBack();
}}>
{this.state.credentialsStep === 0 ? 'Cancel' : 'Back'}
</Button>
</Box>
</Grid>
</StepContent>
</Step>
))
}
</Stepper>
</DialogContentText>
</DialogContent>

Resources