Make overlay in react load only when input is clicked - reactjs

I used the code by #WitVault to display an overlay when my button 'add data' is clicked; It works fine but the overlay loads whenever the page is loaded. I have to close the overlay to see my main content.
I want the overlay to appear only when the button is clicked and not when the page loads. Here's my code:
class registration extends Component{
constructor(props) {
super(props);
this.state = {
style : {
width : "100%"
}
};
this.openNav = this.openNav.bind(this);
this.closeNav = this.closeNav.bind(this);
}
componentDidMount() {
document.addEventListener("click", this.closeNav);
}
componentWillUnmount() {
document.removeEventListener("click", this.closeNav);
}
openNav() {
const style = { width : "100%" };
this.setState({ style });
document.body.style.backgroundColor = "rgba(0,0,0,0.4)";
document.addEventListener("click", this.closeNav);
}
closeNav() {
document.removeEventListener("click", this.closeNav);
const style = { width : 0 };
this.setState({ style });
document.body.style.backgroundColor = "#F3F3F3";
}
render(){
return(
<div class="encloser" id="test1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div>
<div class="addbuttondiv">
<button class="addbutton" onClick={this.openNav}>Add Data</button>
<div ref="snav" className = "overlay" style={this.state.style}>
<div className = "sidenav-container">
<div className = "text-center">
<h2>Form</h2>
<p>This is a sample input form</p>
</div>
<a href = "javascript:void(0)"
className = "closebtn"
onClick = {this.closeNav}
>
×
</a>
</div>
</div>
</div>
</div>
//some html content
</div>
);
}
}
export default registration;
CSS:
/* The Overlay (background) */
.overlay {
/* Height & width depends on how you want to reveal the overlay (see JS below) */
height: 100%;
width: 0;
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
left: 0;
top: 0;
background-color: rgb(0,0,0); /* Black fallback color */
background-color: rgba(0,0,0, 0.9); /* Black w/opacity */
overflow-x: hidden; /* Disable horizontal scroll */
transition: 0.5s; /* 0.5 second transition effect to slide in or slide down the overlay (height or width, depending on reveal) */
}
.overlay-content {
position: relative;
top: 25%; /* 25% from the top */
width: 100%; /* 100% width */
text-align: center; /* Centered text/links */
margin-top: 30px; /* 30px top margin to avoid conflict with the close button on smaller screens */
}
.overlay .closebtn {
position: absolute;
top: 20px;
right: 45px;
font-size: 60px;
}
/* When the height of the screen is less than 450 pixels,
change the font-size of the links and position the close button again, so they don't overlap */
#media screen and (max-height: 450px) {
.overlay a {font-size: 20px}
.overlay .closebtn {
font-size: 40px;
top: 15px;
right: 35px;
}
}

You have to set width as "0" in constructor like below:
class registration extends Component{
constructor(props) {
super(props);
this.state = {
style : {
width : "0"
}
};
this.openNav = this.openNav.bind(this);
this.closeNav = this.closeNav.bind(this);
}
componentDidMount() {
document.addEventListener("click", this.closeNav);
}
componentWillUnmount() {
document.removeEventListener("click", this.closeNav);
}
openNav() {
const style = { width : "100%" };
this.setState({ style });
document.body.style.backgroundColor = "rgba(0,0,0,0.4)";
document.addEventListener("click", this.closeNav);
}
closeNav() {
document.removeEventListener("click", this.closeNav);
const style = { width : 0 };
this.setState({ style });
document.body.style.backgroundColor = "#F3F3F3";
}
render(){
return(
<div class="encloser" id="test1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div>
<div class="addbuttondiv">
<button class="addbutton" onClick={this.openNav}>Add Data</button>
<div ref="snav" className = "overlay" style={this.state.style}>
<div className = "sidenav-container">
<div className = "text-center">
<h2>Form</h2>
<p>This is a sample input form</p>
</div>
<a href = "javascript:void(0)"
className = "closebtn"
onClick = {this.closeNav}
>
×
</a>
</div>
</div>
</div>
</div>
//some html content
</div>
);
}
}
export default registration;

Related

Apply CSS transition to styled-component when React state changes

I have some state that changes after button click. The state changes the size of a sidebar.
Here is my CSS made with styled-components and conditional rendering:
const SidebarStyled = styled.div`
width: ${this.state.sidebarOpen ? '200px' : '70px'};
position: fixed;
left: 0px;
top: 0px;
height: 100vh;
background-color: #0c1635;
display: flex;
flex-direction: column;
`;
Any idea how I can apply a transition 0.2s on the conditional rendering?
I have tried to add transition: all 0.2s ease-in-out; and it didn't work.
As I mentioned in my comment, you need to pass in a prop and interpolate it out to change your CSS. Otherwise your component will re-render, and the CSS transition won't be applied.
const { React, ReactDOM, styled } = window;
class WontWork extends React.Component {
constructor(props) {
super(props);
this.state = { sidebarOpen: false };
}
render() {
const Sidebar = styled.div`
width: ${this.state.sidebarOpen ? "200px" : "70px"};
height: 20px;
background: red;
transition: width 1s;
`;
return (
<main>
<p>This won't work:</p>
<Sidebar />
<button
onClick={() => this.setState({ sidebarOpen: !this.state.sidebarOpen })}
>
Expand
</button>
</main>
);
}
}
const WorkingSidebar = styled.div`
width: ${(props) => (props.open ? "200px" : "70px")};
height: 20px;
background: green;
transition: width 1s;
`;
class WillWork extends React.Component {
constructor(props) {
super(props);
this.state = { sidebarOpen: false };
}
render() {
return (
<main>
<p>You need to pass in a <b>prop</b> to a predefined styled-component:</p>
<WorkingSidebar open={this.state.sidebarOpen} />
<button
onClick={() => this.setState({ sidebarOpen: !this.state.sidebarOpen })}
>
Expand
</button>
</main>
);
}
}
ReactDOM.render(
<div>
<WontWork />
<hr />
<WillWork />
</div>,
document.getElementById("app")
);
<script crossorigin src="https://unpkg.com/react#16.14.0/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16.14.0/umd/react-dom.development.js"></script>
<script crossorigin src="https://unpkg.com/react-is#16.13.1/umd/react-is.production.min.js"></script>
<script crossorigin src="https://unpkg.com/styled-components#5.3.3/dist/styled-components.min.js"></script>
<div id="app"></div>
Try this:
You can passe sidebarOpen as props:
<SidebarStyle sidebarOpen = {this.state.sidebarOpen}>
Then:
const sidebarStyle = styled.div`
width: 70px;
transition: transform .2s ease-in-out;
transform: ${props.sidebarOpen ? "scaleX(3)" : "scaleX(1)"};
.
.
.
`
I helped from here:
See here: Adding transitions to styled components
Does it work In this case?
Add a transition property like: transition:all 200ms ease-in;

How to open a particular accordion based click event in reactjs and autoclose remaining accordion?

I want to open a particular Section on clicking on that. How to do that by using click event? And also auto close the remaining accordion if I click on another accordion. Here is my code.
Accordion Component
import React, { Component } from 'react';
import Section from './section';
class Accordion extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = {
open: false,
headingClassName: 'accordion-heading',
className: 'accordion-content accordion-close',
Label: 'label-close',
icon: "+",
selectedItem: null,
};
}
handleClick = () => {
const open = this.state.open;
if (open) {
this.setState({
open: false,
className: "accordion-content accordion-close",
headingClassName: "accordion-heading",
Label: 'label-close',
icon: "+",
})
} else {
this.setState({
open: true,
className: "accordion-content accordion-open",
headingClassName: "accordion-heading clicked",
Label: 'label-open',
icon: "-",
})
}
}
render() {
return (
<div className="accordion-container">
<h1>Accordian Component</h1>
How to pass id as parameter in each section in onClick event to open
particular accordion and to autoclose remaining.
<Section>
<div className={this.state.headingClassName} onClick={this.handleClick} id="1">
<h3>One</h3> <label className={this.state.Label}>{this.state.icon}</label>
</div>
<div className={this.state.className}>
<p>This is paragraph</p>
</div>
</Section>
<Section>
<div className={this.state.headingClassName} onClick={this.handleClick} id="2">
<h3>Two</h3> <label className={this.state.Label}>{this.state.icon}</label>
</div>
<div className={this.state.className}>
<p>This is paragraph</p>
</div>
</Section>
<Section>
<div className={this.state.headingClassName} onClick={this.handleClick} id="3">
<h3>Three</h3> <label className={this.state.Label}>{this.state.icon}</label>
</div>
<div className={this.state.className}>
<p>This is paragraph</p>
</div>
</Section>
</div>
);
}
}
export default Accordion;
Section Component
import React, { Component } from 'react';
class Section extends Component {
render() {
return (
<div className="parent-accordion">
{this.props.children}
</div>
);
}
}
export default Section;
CSS
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
.accordion-container {
margin: auto;
width: 700px;
}
.accordion-container h1 {
color: #0000007a;
text-align: center;
font-family: sans-serif;
}
.parent-accordion {
width: 100%;
border: 1.5px solid #00000017;
}
.accordion-heading {
padding: 5px 5px;
background-color: #e2e2e254;
cursor: pointer;
text-transform: capitalize;
/* font-size: 17px; */
/* font-weight: 600; */
color: #2b2b41;
/* font-family: sans-serif; */
transition: background-color 1s;
}
.accordion-heading:hover {
background-color: #000000c7;
color: white;
First of all i've encompased a minimal (no css) example of how an accordion would behave on codesandbox, here.
This can be done multiple ways. In the example above the body of the tab is hidden with display:none if the tab is not active.Basically you iterate over your data in the render function and that's where you set your classes based on whatever flags you want (in your case isActive). You could render a Section for each tab and pass props to it.
The click handler updates your state with the id of the active tab.

My sliding menu in React does not work?

follow the tutorial but apparently does not work as it should, by pressing the button should appear the menu on the right side but it appears in this way, what is wrong?
the MenuContainer class change it to SideBar.js
all classes are inside SideBar.js
import React, { Component } from "react";
class SideBar extends React.Component {
constructor(props) {
super(props);
this.state = { visible: false };
this.handleMouseDown = this.handleMouseDown.bind(this);
this.toggleMenu = this.toggleMenu.bind(this);
}
toggleMenu() {
this.setState({
visible: !this.state.visible
});
}
handleMouseDown(e) {
this.toggleMenu();
console.log("clicked");
e.stopPropagation();
}
render() {
return (
<div>
<MenuButton handleMouseDown={this.handleMouseDown}/>
<Menu handleMouseDown={this.handleMouseDown} menuVisibility={this.state.visible}/>
<div>
<div>
<p>Can you spot the item that doesn't belong?</p>
<ul>
<li>Lorem</li>
<li>Ipsum</li>
<li>Dolor</li>
<li>Sit</li>
<li>Bumblebees</li>
<li>Aenean</li>
<li>Consectetur</li>
</ul>
</div>
</div>
</div>
);
}
}
export default SideBar;
class MenuButton extends React.Component {
render() {
return (
<button className="roundButton"
onMouseDown={this.props.handleMouseDown}></button>
);
}
}
class Menu extends React.Component {
render() {
var visibility = "hide";
if (this.props.menuVisibility) {
visibility = "show";
}
return (
<div className="flyoutMenu"
onMouseDown={this.props.handleMouseDown}
className={visibility}>
<h2>Home</h2>
<h2>About</h2>
<h2>Contact</h2>
<h2>Search</h2>
</div>
);
}
}
and my styles.scss
.roundButton {
background-color: #96D9FF;
margin-bottom: 20px;
width: 50px;
height: 50px;
border-radius: 50%;
border: 10px solid #0065A6;
outline: none;
transition: all .2s cubic-bezier(0, 1.26, .8, 1.28);
}
.roundButton:hover {
background-color: #96D9FF;
cursor: pointer;
border-color: #003557;
transform: scale(1.2, 1.2);
}
.roundButton:active {
border-color: #003557;
background-color: #FFF;
}
.flyoutMenu {
width: 100vw;
height: 100vh;
background-color: #FFE600;
position: fixed;
top: 0;
left: 0;
transition: transform .3s
cubic-bezier(0, .52, 0, 1);
overflow: scroll;
z-index: 1000;
}
.flyoutMenu.hide {
transform: translate3d(-100vw, 0, 0);
}
.flyoutMenu.show {
transform: translate3d(0vw, 0, 0);
overflow: hidden;
}
This is the image of how it is displayed when you click on it.
image
you mutate the state from SideBar component. Sidebar component passes down state to Menu as a prop. When you mutate this state, it should re-render the Menu component with the new value.
Your menu class would look something better like:
class Menu extends React.Component {
render() {
const { menuVisibility } = this.props
return (
<div className="flyoutMenu"
onMouseDown={this.props.handleMouseDown}
className={menuVisibility ? 'show' : 'hide'}>
<h2>Home</h2>
<h2>About</h2>
<h2>Contact</h2>
<h2>Search</h2>
</div>
);
}

Forward Parent onWheel to Scroll Table

I have an outer parent <div /> container that contains a <Table /> element. I'd like to be able to scroll the <Table /> on the onWheel event of the parent <div /> element, even if the mouse is not currently over the <Table />.
I have a ref to the table element and an event handler listening for the onWheel event but I haven't been able to figure out how to forward that event down to the table.
Because I guess that you want to scroll the table body, you can try with this.
class Table extends React.Component {
constructor() {
super();
this.callback = this.callback.bind(this);
this.body = null;
}
callback(ev) {
this.body.scrollTop += ev.deltaY;
}
render() {
return <div onWheel={this.callback}>
<table>
<tbody ref={c => this.body = c}>
{[1, 2, 3, 4, 5, 6,].map(i => <tr>
<td>{i}</td>
</tr>)}
</tbody>
</table>
</div>;
}
}
ReactDOM.render(<Table />, document.getElementById('root'));
tbody {
display: block;
height: 3rem;
overflow: scroll;
}
tr:nth-child(2n+1) {
background-color: #ddf;
}
tr:nth-child(2n) {
background-color: #eef;
}
table {
margin: auto;
border-collapse: collapse;
}
td {
width: 5rem;
text-align: center;
font-family: sans-serif;
color: #00f;
}
div {
width: 100%;
display: block;
text-align: center;
background-color: #99f;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
I made a codePen illustrating a scroll redirection
This will listen wheelEvent on a parent <div>(the one with a red background), disable the default scrolling behavior (evt.preventDefault()) then set the scrollTop position of another <div>.
Here's the component code :
class RedirectScroll extends React.Component {
parentOnScroll = (evt) => {
evt.preventDefault();
const scrollTo= (evt.deltaY) + this.box.scrollTop;
this.box.scrollTop = scrollTo;
}
render() {
return (
<div className="parent" onWheel={this.parentOnScroll}> // Listen scrolls on this div
<div className="scrollablebox" ref={(box) => this.box = box}>
// Some content
</div>
</div>
);
}
}
I hope this is what you're looking for.

React sharable panel url

Consider my following snippet. Right now on button click it opens a div-three that loads AnotherComponent.The url is simply 'http://localhost:3000/de' i.e. Indexroot
What I want to achieve is: If I hit 'http://localhost:3000/de/?open' then I want the panel i.e. div-three already open.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
showThird: false
}
this.showDivThree = this.showDivThree.bind(this)
/*if(props.location.search=="?open"){
this.showDivThree()
}*/
}
showDivThree() {
this.setState(prevState => ({ showSecond: false, showThird: !prevState.showThird}))
console.log(this.state)
}
render() {
return (
<div className={'wrapper' + ( this.state.showThird ? ' show' : '')}>
<div className="one">one
{/* Show third */}
<div>
<button onClick={this.showDivThree}>{this.state.showThird ? 'hideThird' : 'showThird'}</button>
</div>
</div>
<div className="three">three
<div>
<button onClick={this.showDivThree}>{this.state.showThird ? 'hideThird' : 'showThird'}</button>
<AnotherComponent />
</div>
</div>
</div>
)
}
}
class AnotherComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<div>
<h4>Another component</h4>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
.wrapper {
overflow: hidden;
white-space: nowrap;
}
.one, .two, .three {
background: #333;
border: 2px solid #787567;
box-sizing: border-box;
color: #fff;
display: inline-block;
font-family: arial;
overflow: hidden;
padding: 20px;
text-align: center;
transition: border 0.2s, padding 0.2s, width 0.2s;
min-height: 50vh;
}
.one {
width: 100%;
}
.two {
border-width: 2px 0;
padding: 20px 0;
width: 0;
}
.three {
border-width: 2px 0;
padding: 20px 0;
width: 0;
}
.show .one, .show .two, .show .three {
border-width: 2px;
padding: 20px;
width: 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://unpkg.com/react-router/umd/react-router.min.js"></script>
<div id="root"></div>
I have commented a code where I read search string from props.location, if it is present then I simply call the function that opens the div-three. But as I have mixed conditions to open divs it somehow is not working.
How can I fix this?
You can't call setState (showDivThree method calls setState) in contructor since when constructor is called component hasn't been mounted yet. Please check this SO answer for more details.
You should move if statement checking URL search string from constructor to componentDidMount method which is called immediately after a component is mounted and in which you can safely use setState:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
showThird: false
};
this.showDivThree = this.showDivThree.bind(this)
}
componentDidMount() {
if (props.location.search == "?open") {
this.showDivThree();
}
}
...
}
Besides, I think that your URL should be without slash before search query. So it should be http://localhost:3000/de?open instead of http://localhost:3000/de/?open.

Resources