Radio button style changes when clicked with React Hooks - reactjs

I want the radio button to change when clicked. This is what i have now image
I want it to change to this when clicked
Here's my code: `
const [active, setIsActive] = useState(false)
<div className={`checkbox payment-radio-btn1 ${active ? "checkbox:hover" : "" }`}>
<input type="radio" value="paystack" name='payment' onChange={handleChange}/>
<label id='paystack'>Paystack (Debit/Credit Card)</label>
</div>
<div className={`checkbox payment-radio-btn2 ${active ? "checkbox:hover" : "" }`}>
<input type="radio" value="wallet" name='payment' onChange={handleChange}/>
<label id='wallet'>Pay with Wallet</label>
</div>
Here's my css code
.checkbox:hover{
border: 2px solid #00B6F0;
background: #FFFFFF;
}
.payment-radio-btn1{
position: absolute;
width: 406px;
height: 64px;
left: 10px;
top: 128px;
background: #F3F4F5;
box-shadow: 0px 24px 38px 3px rgba(0, 0, 0, 0.14);
border-radius: 4px;
margin-top: 20px;
margin-left: 6px;
display: flex;
}

One option is a custom Radio element that allows you to represent your radio buttons however you like. In this example we use two emoji, but you could use images, or SVG if you wanted.
function Radio({ checked, onClick, children, on = "✔️", off = "🟡" }) {
return <div className="radio" onClick={onClick}>
{checked ? on : off } {children}
</div>
}
We can use the Radio elements in our app like this.
function App() {
const [radio, selectRadio] =
useRadio(["paystack", "paypal", "wallet"], "paystack")
return <div>
<Radio checked={radio == "paystack"} onClick={selectRadio("paystack")}>
Paystack (Debit/Credit Card)
</Radio>
{/* more radio options ...*/}
</div>
}
This is made possible by writing useRadio which encodes the radio group logic nicely in a custom hook.
function useRadio(validStates, initState) {
const [state, setState] = React.useState(initState)
return [
state,
value => event =>
validStates.includes(value)
? setState(value)
: console.error(`invalid option: ${value}`)
]
}
Here's a minimal, verifiable example. Run it below and click some radio buttons to see the application state change.
function App() {
const [radio, selectRadio] = useRadio(["paystack", "paypal", "wallet"], "paystack")
return <div>
<Radio checked={radio == "paystack"} onClick={selectRadio("paystack")}>
Paystack (Debit/Credit Card)
</Radio>
<Radio checked={radio == "wallet"} onClick={selectRadio("wallet")}>
Pay with Wallet
</Radio>
<Radio checked={radio == "paypal"} onClick={selectRadio("paypal")}>
PayPal
</Radio>
<pre>{JSON.stringify({paymentOption: radio}, null, 2)}</pre>
</div>
}
function Radio({ checked, onClick, children, on = "✔️", off = "🟡" }) {
return <div className="radio" onClick={onClick}>
{checked ? on : off } {children}
</div>
}
function useRadio(validStates, initState) {
const [state, setState] = React.useState(initState)
return [
state,
value => event =>
validStates.includes(value)
? setState(value)
: console.error(`invalid option: ${value}`)
]
}
ReactDOM.render(<App/>, document.querySelector("#app"))
.radio { cursor: pointer; }
pre { padding: 0.5rem; background-color: #ffc; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>

Related

How to toggle button color with className in react?

I am trying to toggle a button with hook, classname and id but all buttons toggle color instead of one button that is actually clicked.
The classname is to toggle classname "dark" and null, where .dark changes the button black.
[duplicate]
I am trying to toggle a button with hook, classname and id but all buttons toggle color instead of one button that is actually clicked.
The classname is to toggle classname "dark" and null, where .dark changes the button black.
import './Clothing.css'
import data from '../../data/data2.json';
const Clothing = () => {
const [toggle, setToggle] = useState(null);
const types = [
{ id: 11, value: 'All' },
{ id: 22, value: 'Cap' },
{ id: 33, value: 'Sweatshirt' },
{ id: 44, value: 'Hoodie' },
{ id: 55, value: 'Shirt' }
]
const handleToggle = (e) => {
console.log(e.target.id)
if (types.filter(
(item) => item.id === e.target.id
)) return setToggle(!toggle)
}
<div className="buttonDiv">
{
types.map((t) =>
<button
key={t.id}
id={t.id}
value={t.value}
className={ toggle ? "dark" : null}
onClick={(e) => {
handleSelectedCategory(e);
handleToggle(e);
}}>
{t.value}
</button>
)
}
</div>
.clothSection {
position: absolute;
top: 25%;
width: 100%;
padding: 0 2rem;
.topMenu {
display: flex;
flex-direction: column;
padding: 2rem 4rem;
.buttonDiv {
gap: 2rem;
display: flex;
padding: 2rem 0;
button {
background-color: var(--InputColor);
padding: .5rem 1rem;
border-radius: .5rem;
font-size: var(--NormalFontSize);
color: var(--TextColor);
cursor: pointer;
border: none;
}
.dark {
background-color: var(--BlackColor);
color: var(--WhiteColor);
}
It is my understanding that you have several buttons. You wish to click a button and have that button dynamically add the .dark class, giving each button its own independent state.
The issue is that you have toggle and setToggle happening in a parent component. Then you render all of your buttons with the current value of toggle. We want each button to contain its own toggle value.
New ClothingItem.js
I added a new component ClothingItem.js, which is responsible for rendering a single clothing item. Notice how this component tracks and sets its own toggle value, utilizing most of the code you had in place to render a button initially.
const ClothingItem = ({ myKey, id, value }) => {
const [toggle, setToggle] = useState(false);
return (
<button
key={myKey}
id={id}
value={value}
className={toggle ? "dark" : null}
onClick={() => {
// handleSelectedCategory(e);
setToggle(!toggle);
}}
>
{value}
</button>
);
};
Updated Clothing.js
We removed all the existing state and the handleToggle() function. In addition, instead of rendering <button>s, we now render <ClothingItem />s, passing in key, id, and value as before.
return (
<div className="buttonDiv">
{types.map((t) => (
<ClothingItem key={t.id} id={t.id} value={t.value} />
))}
</div>
);
Hello you should use classnames like this:
classNames({ dark: toggle })

How can i create a new div when i onclick the button in React js?

code 1 component:-
const TableheaderText = props => {
//const [playlist, setPlaylist] = useState(props);
const [playlist, setPlaylist] = useState("playlist");
const [showing, SetShowing] = useState();
const [isActive, setActive] = useState(true);
//console.log(playlist);
useEffect(() => {
// setPlaylist(props);
SetShowing("PLAYLIST:");
setPlaylist(props.val);
}, [props])
return (
<div className="mainContent">
<div className="tableHeaderBody" >
<div className="TableText" >
<div id="HIDE">{showing}</div><div id="SHOW">{playlist}</div>
</div>
<div className="ClossIcon"><FaCircle style={{ color: "#FC0000", width: "10px", height: "10px", alignItems: "right" }} /></div>
</div>
</div>
)
}
code 2 component:-
<NavLink to={`/Table`} onClick={(e) => myClick(val, index)} >
<button className='notActive buttonLeft'
onClick={() => handleOnClick(index)} // pass the index
className={activeIndex === index ? "active" : "notActive"}>
{val}
</button>
</NavLink>
Right now i have one div and when i click the menu value then one div replace the name
but i want that when i click the 1 value its create one div and when click the 2 value its create second div with the name of 2 div and place right side of 1 div and so.. (if 3,4 value menu ..)
This may be one possible solution to achieve the desired objective (copied from OP's question):
i want that when i click the 1 value its create one div and when click
the 2 value its create second div with the name of 2 div and place
right side of 1 div and so..
Code Snippet
const {useState} = React;
const Thingy = () => {
const myDivs = [...Array(4).keys()].map(i => `My Div # ${i+1}`);
const [flipDivs, setFlipDivs] = useState([
...myDivs.map(
(text, id) => ({id, text, show: false})
)
]);
const handleClick = e => {
const idx = e.target.id;
const newArr = [...flipDivs];
newArr[idx].show = !flipDivs[idx].show;
setFlipDivs(newArr);
};
const myButtons = [...Array(4).keys()];
return (
<div>
<div class="allDivs">
<div> Fixed Div </div>
{
flipDivs.filter(({show}) => !!show).map(
({text, id, show}, idx) => (
<div
key={idx}
class="simpleMargin rightBorder"
>
{text}
</div>
)
)
}
</div>
<div class="buttons">
{myButtons.map(id => (
<button
id={id}
class="simpleMargin"
onClick={handleClick}
>
{flipDivs[id].show ? 'Hide' : 'Show'} Div # {id+1}
</button>
))}
</div>
</div>
);
};
ReactDOM.render(
<div>
DEMO
<Thingy />
</div>,
document.getElementById("rd")
);
.allDivs {
border: 2px solid black;
width: fit-content;
display: flex;
align-items: center;
margin: 10px 15px;
}
.simpleMargin { margin: 5px 10px; }
.rightBorder { border: 2px solid black; }
.buttons {
display: flex;
margin: 10px 5px;
}
<div id="rd" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
Explanation
simple, straightforward approach
Add a flag to determine which div needs to be rendered on which button click
On the click-handler, simply update the flag to show / hide div
For this you need to make a div element and whoe it conditionally ( with state declared with useState ) and then toggle the state on button click to show it. like :
{
showDiv ? <div></div> : null
}
Here showDiv is:
const [showDiv, setShowDiv] = useState (false)
Now toggle showDiv on button click to true. :)

How can i hover in React using useState

I wanna toggle a class when hovering on a Container by changing the opacity from 0 to 1, I've used onmouseEnter and onMouseLeave Event to toggle the class, but when I console hover state I see that is changing from true to false when I hover but the class "Show" is not changing.
What do you think ?
<--Components-->
import React,{useState} from 'react';
import './MyWork.css';
import {Visibility, GitHub } from "#material-ui/icons";
const SingleProject = ({src, title}) => {
const [hover, isHover] = useState(false);
const showIcons = isHover ? "Show" : "";
return (
<div className="card-container" onMouseEnter={()=> isHover(true)} onMouseLeave={()=> isHover(false)}>
<img src={src} alt={title}/>
<h1 id="card-title">{title}</h1>
<div className={`Info ${showIcons}`}>
<div className="Icon">
<GitHub/>
</div>
<div className="Icon">
<Visibility/>
</div>
</div>
</div>
)
}
export default SingleProject;
<--- Css--->
.card-container {
height: 314px;
width: 500px;
cursor: pointer;
position : relative;
}
.Info {
position: absolute;
height: 100%;
width: 100%;
top:0;
left:0;
display:flex;
justify-content:center;
align-items: center;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
}
.Info.Show {
opacity: 1;
}
When assigning the value to showIcons, you need to use hover instead of isHover which is the setter function for that state.
Additionally, I recommend naming the setter function setHover to avoid confusion and be more semantic. You can also add conditional Show class like this, which is more concise:
iconst SingleProject = ({src, title}) => {
const [hover, setHover] = useState(false);
return (
<div
className="card-container"
onMouseEnter={()=> setHover(true)}
onMouseLeave={()=> setHover(false)}
>
<img src={src} alt={title}/>
<h1 id="card-title">{title}</h1>
<div className={`Info ${hover ? "Show" : ""}`}>
<div className="Icon">
<GitHub/>
</div>
<div className="Icon">
<Visibility/>
</div>
</div>
</div>
)
}
export default SingleProject;
You are using the setter instead of the state itself on your condition. Change isHover with hover like below:
const showIcons = hover ? "Show" : "";

ReactJS DropZone browser attempts to open file on drop

Trying to implement the Dropzone component but not have much luck. Am I missing something here?
import { useState } from 'react';
import { useDropzone } from 'react-dropzone';
import styled from 'styled-components';
export const FilDataForm = (props) => {
const [files, setFiles] = useState([])
const getColor = (props) => {
if (props.isDragAccept) return '#00e676';
if (props.isDragReject) return '#ff1744';
if (props.isDragActive) return '#2196f3';
return '#eeeeee';
}
const onDrop = (file) => {
console.log('HERE!!!!!')
let nf = files;
nf.push(file)
setFiles(nf)
}
const Container = styled.div`
flex:1;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
border-width: 2px;
border-radius: 2px;
border-color: ${props => getColor(props)};
border-style: dashed;
background-color: #fafafa;
color: #bdbdbd;
outline: none;
transition: border .24s ease-in-out;
`
const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone(onDrop);
return (
<div className="modal">
<div className="dialog" style={{ width: "25%", marginBottom: "50px" }}>
<div className="header"><h2>File Uploader</h2></div>
<div className="content">
<Container {...getRootProps({ isDragActive, isDragAccept, isDragReject })}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</Container>
<div className="grid-container" style={{ marginTop: "20px", height: "250px" }}></div>
</div>
</div>
</div>
)
}
Dragging the file(s) into the drop area causes the browser to launch a new tab attempting to open the file. Any help is appreciated.
EDIT
Clicking in the Dropzone does not open the file dialog either.
You need to prevent the default event.
I'm using Class component based React Dropzone and this is how i have stopped the default event.
{...getRootProps({
className: 'dropzone',
onDrop: (event) => event.preventDefault(),
})}
Complete Code
<Dropzone onDrop={ (files) => fileHandling(files) } >
{({ getRootProps, getInputProps }) => (
<div
{...getRootProps({
className: 'dropzone',
onDrop: (event) => event.preventDefault(),
})}
style={{ border: '1px solid #707070' }}
>
<input {...getInputProps()} />
<h3 style={{ cursor: 'pointer' }}>
Drag & Drop file or click here to Upload
</h3>
</div>
)}
</Dropzone>
Hope it helps

add background color onClick in react

so i have this flexbox:
[![flexbox][1]][1]
what i need is this:
when i press on any the divs on the left from overview to the bottom i need it to be colored in white the background just like in the image, i'm new to react and i'm trying to go through this project can anyone help me with this i'm stuck.
code so far:
flexbox.js:
const sidebar = (props) => (
<div>
<div className="container">
<div className="flex-item item-1" onClick={}>John Smith</div>
<div className="flex-item item-2">Male, 26 years old</div>
<div className="flex-item item-3">Overview</div>
<div className="flex-item item-4">Alerts</div>
<div className="flex-item item-5">Recent</div>
<div className="flex-item item-6">Blood Pressure</div>
<div className="flex-item item-7">Body Weight</div>
<div className="flex-item item-8">Glucose</div>
<div className="flex-item item-9">SpO2</div>
<div className="flex-item item-10"><FontAwesomeIcon icon={faCog}/></div>
</div>
</div>
);
flexbox.css:
.container {
border: 2px solid #57c0e8;
background-color: #57c0e8;
margin-top: 4%;
float: left;
border-top-right-radius: 20px;
border-bottom-right-radius: 20px;
color:white;
display: flex;
flex-direction: column;
height:40rem;
width:15rem;
flex-wrap: wrap;
justify-content: flex-start;
align-items: flex-start;
font-size:0.9rem;
}
.flex-item{
margin-top: 2rem;
}
.item-2 {
margin-top: 0rem;
}
.item-3 {
margin-top: 5rem;
}
.item-10{
align-self:center;
}
If you really want to keep your code as it is now, you could simply add a class on each flex item and an onClick method to add a class on the selected item and remove the class on the others.
here is how you can do that :
const MyList = () => {
const setSelectedItem = e => {
Array.from(document.getElementsByClassName("item"))
.forEach(item => item.classList.remove("selected"));
e.target.classList.add("selected");
};
return (
<div>
<ul>
<li className="item" onClick={setSelectedItem}>
item 1
</li>
<li className="item" onClick={setSelectedItem}>
item 2
</li>
<li className="item" onClick={setSelectedItem}>
item 3
</li>
<li className="item" onClick={setSelectedItem}>
item 4
</li>
</ul>
</div>
);
};
But I suggest you to refactor your code to build your sidebar list dinamically, It will be way easier to manage. You can do it this way, with an array containing your data and looping over it :
import React, { Component } from "react";
import { render } from "react-dom";
import Hello from "./Hello";
import "./style.css";
const App = () => {
const data = [
{ name: "item 1", isSelected: false },
{ name: "item 2", isSelected: false },
{ name: "item 3", isSelected: false },
{ name: "item 4", isSelected: false }
];
const [items, setItems] = React.useState(data);
const setSelectedItem = selectedItem => {
const newItems = [...items];
newItems.forEach(item => {
item.isSelected = item.name === selectedItem.name;
});
setItems(newItems);
};
const buildList = () => {
return items.map(item => (
<li className={item.isSelected ? 'selected':''} onClick={() => setSelectedItem(item)}>
{item.name}
</li>
));
};
return <ul>{buildList()}</ul>;
};
render(<App />, document.getElementById("root"));
Then you only have to write the css on .selected:
li{
padding: 10px;
}
.selected{
background-color: lightskyblue;
border-radius: 50px 0 0 50px;
box-shadow: 2px 2px 5px lightgray;
}
Here is the repro on stackblitz.
Here is used a list but it changes nothing compared to you using flexbox.
Ok, so I'm thinking you could do it by making an active class in your css to make it white:
.sidebarActive {
background:#fff
...
...
}
Then, add a state to your component that can store a string (Or I guess it could be a number and your could store the index of the selected div). This would looks something like:
const sidebar = (props) => {
const [selectedDiv,setSelectedDiv] = React.useState(null)
return (
<div>
<div className="container">
<div className="flex-item item-1" onClick={}>John Smith</div>
...
</div>
</div>
)
}
Then, your onClick function needs to set the state to the correct div:
<div className="flex-item item-1" onClick={()=>setSelectedDiv('John Smith')}>John Smith</div>
And finally, you need to add a conditional to the classNames of the divs - to check if the state is selecting this div:
<div className={
selectedDiv === "John Smith"
?
"flex-item item-1 sidebarActive"
:
"flex-item item-1"
}
onClick={...}
>
John Smith
</div>
There are then many ways to optimise this - Like adding your divs into an array, so that you don't need to type "John Smith", "Overview", "Alerts" and all the rest of them multiple times.
But, this should be enough info to get you somewhere!
Hope it helps :)

Resources