React/Redux/CSS - Modal placement - javascript

i have a Card and a Modal component like so
class Card extends Component {
constructor() {
super();
this.state = { showModal: false }
}
render() {
const { showModal } = this.state;
return (
{/* Some code */}
{showModal && <Modal />}
)
}
}
So, I don't want to render my Modal until it is required. Logic.
The Modal's job, in this context, is to display the full content of the Card component (The Card has a fixed height, so I cannot displaying every bit of information in there).
Now, at a higher level I have the following:
class App extends Component {
/* Some Code */
render() {
return (
<div>
<Content /> {/* Our content */}
<Overlay /> {/* Our all-purpose-overlay (we need it for the Modal) */}
</div>
)
}
}
The problem is that my Card component has the style position: relative and the Modal component has the a z-index and the style position: absolute.
I did some research and I read that nested elements with non-static
position will not work the same way regarding the z-index. The z-index will take effect only within the non-static element.
So I cannot make my Modal appear above the the Overlay component. Furthermore, The Card component has a overflow:hidden property. And so, the Modal gets cropped.
Here is a simple demonstration.
function toggleModal() {
var app = document.getElementById("app");
app.classList.toggle("-modal");
}
:root {
background: #ddd;
}
#app,
#overlay {
height:100vh;
width:100%;
}
#app {
display: flex;
align-items: center;
justify-content: center;
}
/* Overlay */
#overlay {
position: absolute;
top: 0;
left: 0;
z-index: 1;
visibility: hidden;
background: rgba(0,0,0,0.3);
}
.-modal #overlay {
visibility: visible !important;
}
/* Card */
#card {
position: relative;
width: 250px;
padding: 1em;
border-radius: 5px;
background: white;
overflow: hidden; /* Problem */
}
.content {
padding: 4em 0;
text-align: center;
}
.btn {
padding: 1em 2em;
border:none;
color:white;
float: right;
cursor: pointer;
transition: 0.2s ease;
background: #00abff;
}
.btn:hover {
background: #0c9de4;
}
/* Modal */
#modal {
width: 300px;
position: absolute;
top:0;
left: 50px; /* Modal Gets clipped */
visibility: hidden;
background-color:red;
}
.-modal #modal {
visibility: visible;
}
<div id="app">
<div id="card">
<div class="content">content</div>
<button class="btn" onclick="toggleModal()">Display Modal</button>
<div id="modal">
<div class="content">
<div>Modal</div>
<div>With same content</div>
<div>(under the Overlay and also cropped)</div>
</div>
</div>
</div>
<div id="overlay" onclick="toggleModal()"></div>
</div>
Question : How should I organize my components so that I do not get this problem?
I thought of having only one Modal at top level. Then I simply display it. But I need to render the children of the Card into the Modal.
How should I proceed?

Since you are using React, what I would actually recommend is to use a Portal to render your modal. One thing Portals solve in React are precisely this issue. If you are using a more recent version of React (16+) then you already have access to portals.
If you are using an older version of React, that is okay. You can use an implementation like this (react-portal) instead.
Now you will have your components/markup rendered in a totally separate React tree outside of the context of your containing <div> that has position: relative on it and you can absolute or fixed position it wherever you need to.

Related

Why a few this same components works differently in react?

I have the following component named Card:
<article className={styles.card_container}>
<input type="checkbox" className={styles.checkbox} onClick={setCheckbox}/>
<div className={styles.text_container} id="txt_container">
<span>
{props.number}
</span>
</div>
</article>
Which should display checkbox, without the tick - container to check or not, with background colors, depends on this checkbox is checked or not.
For example, when unchecked this should has red color, but when checked - black.
For this, I decided to use state:
const [isChecked, setChecked] = useState(false);
const setCheckbox = (e) => {
if (isChecked===true){
setChecked(false);
document.getElementById("txt_container").style.backgroundColor="#a81616";
}else {
setChecked(true);
document.getElementById("txt_container").style.backgroundColor="#000";
}
}
I wanted to create a few this type of components so I decided to map this with information from array:
{data.map(element=>
<Card number={element.option} key={element.option}/>)
}
(Where data is an array with object with numbers, Card is created components with code above).
The problem is that, when I "check" other components, it change color only at first.
Why did it happen? I appreciate for any help.
And there some css code:
.card_container {
position: relative;
width: 60px;
height: 45px;
margin: 5px;
float: left;
border: 2px solid #50bcf2;
box-sizing: border-box;
}
.text_container {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
line-height: 25px;
transition: .5s ease;
}
.checkbox {
position: absolute;
top: 0;
left: 0;
width: 60px;
height: 45px;
opacity: 1;
cursor: pointer;
}
I would like to do this by js, is there other way to do this (not by css)? Or maybe can I inject background color provided by props from for example an array to Card component?
You can use style attribute on react component
<div className={styles.text_container} style={{backgroundColor: isChecked? #a81616 : #000}}>
your code doesnt work, because ID is supposed to be unique and you are only selecting first occurence... if you want to work with DOM in react, dont use getElementByID and use useRef() from react. Its more "reactish" way how to do it.

Maintain responsive image height

I am attempting to create a CTA component at the top of my react application, that contains the navbar and the CTA text. After successfully completing the component, I am noticing a minor bug that I would like to resolve. I am only providing my image with a width of 100% and no defined height. This causes the divs beneath the image to flicker upwards until the image has fully loaded. I know not providing the image with a defined height is causing it because the bug goes away when I provide the image with a random height. I am wondering if there is a way to provide the image with a responsive height that would behave in a similar way to just providing my image with 100% width.
my css code is as follows:
body {
margin: 0;
padding: 0;
}
.container {
position: relative;
}
.container .container-background {
opacity: 0.25;
}
.container-background-img {
width: 100%;
position: relative;
}
.container .content {
position: relative;
z-index: 1;
}
.app-outer {
max-width: 1170px;
margin: 0 auto;
position: relative;
padding: 0rem 1rem;
}
#media only screen and (max-width: 1170px) {
.container-background-img {
height: 656px;
object-fit: cover;
}
}
#media only screen and (max-width: 768px) {
.container-background-img {
height: 653px;
object-fit: cover;
}
}
/* CODE ADDED */
#navbar {
position: absolute;
top: 0;
left: 0;
right: 0;
}
#content {
position: absolute;
top: 20%;
}
my jsx code is as follows:
import React from "react";
import "./styles.css";
export default function App() {
return (
<>
<div className="container">
<div className="container-background">
<img
id="rob"
src="https://i.imgur.com/iyFtMNA.jpg"
alt="bg"
className="container-background-img"
/>
</div>
<div id="content" className="content">
I am the CTA
</div>
<div id="navbar">
<div
style={{
backgroundColor: "white",
height: 100,
width: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center"
}}
>
I am the navbar
</div>
</div>
</div>
<div>I am beneath the cta</div>
</>
);
}
the following link I have provided contains a code sandbox: https://codesandbox.io/s/issue-react-forked-4lsdm?file=/src/App.js:0-868
Please Note: *** within the code sandbox the issue is not very apparent, but within my react application it is much more noticeable
As you mentioned, the issue is not really clear to see from your sandbox code.
I am not sure this would fix your issue but instead of using image tag try setting your CTA component to have background-image() instead.
Make sure to add other background css attributes too such as
background-repeat: no-repeat;
background-size: cover;
background-posistion: center;
padding-bottom: 60%;
Make sure to add padding-bottom: 60% (Your image seems to have a 3:2(w:h) ratio);
Hopefully, this works for you!

Unable to implement a side Navbar using React

I wanted to implement a hamburger side navbar using react but I am unable to implement the changes that must be displayed on Clicking the hamburger. I am still learning React so please explain what am I doing wrong and feel free to suggest an alternative approach. Here is my code.
import React from 'react';
import * as FaIcons from "react-icons/fa";
class Navbar extends React.Component {
constructor() {
super();
this.state = {
navbarState : 1,
style : {}
}
}
openNav() {
this.setState({"width" : "250px"});
}
closeNav() {
this.setState({"width" : "0px"});
}
handleClick() {
this.setState((prevState) => {
if(prevState.navbarState === 0) {
return {navbarState : 1, style : {width : '250px'}};
}
else {
return {navbarState : 0, style : {width : '0px'}};
}
});
}
render() {
return (
<div>
<div id="mySidenav" className="sidenav" style={this.state.style} >
{console.log(this.state.navbarState)}
<a href="#" className="closebtn" onClick={() => this.handleClick}>×</a>
About
Services
Clients
Contact
</div>
<span onClick={() => this.handleClick}>
{/* <FaIcons.FaBars /> */}
<div className = "hamburger">
<div className="line"></div>
<div className="line"></div>
<div className="line"></div>
</div>
</span>
</div>
);
}
}
export default Navbar;
And my CSS is as follows :
.hamburger{
position: absolute;
cursor: pointer;
margin: 5px;
right: 5%;
top: 5%;
}
.line{
width: 30px;
height: 3px;
background: white;
margin: 5px;
}
.sidenav {
height: 100%; /* 100% Full-height */
width: 0; /* 0 width - change this with JavaScript */
position: fixed; /* Stay in place */
z-index: 1; /* Stay on top */
top: 0; /* Stay at the top */
right: 0;
background-color: black; /* Black*/
overflow-x: hidden; /* Disable horizontal scroll */
padding-top: 60px; /* Place content 60px from the top */
transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */
}
.sidenav-active {
height: 100%; /* 100% Full-height */
width: 250px; /* 0 width - change this with JavaScript */
position: fixed; /* Stay in place */
z-index: 1; /* Stay on top */
top: 0; /* Stay at the top */
right: 0;
background-color: black; /* Black*/
overflow-x: hidden; /* Disable horizontal scroll */
padding-top: 60px; /* Place content 60px from the top */
transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */
}
/* The navigation menu links */
.sidenav a, .sidenav-active a {
padding: 8px 8px 8px 32px;
text-decoration: none;
font-size: 25px;
color: white;
display: block;
transition: 0.3s;
}
/* When you mouse over the navigation links, change their color */
.sidenav a:hover, .sidenav-active a:hover {
color: #f1f1f1;
}
/* Position and style the close button (top right corner) */
.sidenav .closebtn, .sidenav-active .closebtn {
position: absolute;
top: 0;
right: 25px;
font-size: 36px;
margin-left: 50px;
}
First it looks like as you're using a Class-Based Component and you're not binding your handleClick function correctly. Solution to this is either to bind it in your constructor or use an arrow function like so:
handleClick = () => { ... }
This will apply similarly to your other two functions. For further information on Arrow Functions and Binding your functions within Class-Based Components see: https://reactjs.org/docs/faq-functions.html
Secondly, I suspect that handleClick being called in your <span>. Instead of
<span onClick={() => this.handleClick} ... />
Try
<span onClick={this.handleClick} ... /> or <span onClick={() => this.handleClick()} ... />
Let me know if this helps!

React whole page scrollbar when component goes offpage

I have an app like this:
as you can see the middle component continues down out of page and that's why I need a scrollbar to scroll down to it. but I can only make it work if I attach it directly on the middle component but I want a regular whole page scrollbar.
here is my app.js
import React, { Component } from 'react';
import OysterView from './components/OysterView.js'
import './uikit/uikit.css';
import './App.css';
import logo from './uikit/assets/images/hrm-white.svg';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<header>
<img src={logo} className="App-logo" alt="HRM"/>
</header>
</div>
<div className="OysterView">
<OysterView />
</div>
</div>
);
}
}
export default App;
I have tried setting it on different places but it does not recognize that the component is out of bounds so cant scroll down the <OysterView /> component is the component that is out of bound so I have tried in CSS
.App {
overflow-y: scroll;
background-color: #fafafa;
position: fixed;
height: 100vh;
width: 100vw;
z-index: -2
}
tried this as well:
html{
height: 100%;
overflow-y: scroll;
margin: 0;
padding: 0;
}
which doesn't add anything at all and that is probably because .App has no height but if I add height the rest of the content gets pushed down so it solves nothing. I have tried adding it to the index.css html as well and that gives me an scrollbar but it cant be scrolled down. so I am al out of ideas here. how should I attack this? z-index on .App?
You do have to scroll the component itself, just make its container full-screen so that the scrollbar will be on the right side of the window.
.modal-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba( 0, 0, 0, .5 );
overflow-y: scroll;
}
.modal-content {
background: red;
margin: 20%;
height: 2000px;
}
Page content
<div class="modal-container">
<div class="modal-content">
Modal content
</div>
</div>

React and Flex layout how to use them

I am trying to use React and flexbox.Normally i can use flexbox at react native but icouldnt achive in react.js
this is my Css file
.wrapper, html, body {
height:100%;
margin:0;
position:absolute;
}
.wrapper {
display: flex;
flex-direction: column;
}
.nav {
background-color: red;
flex:1
}
.main {
background-color: blue;
flex:1
}
This is my js file
import React, { Component } from 'react';
import './background.css';
import { Icon } from 'semantic-ui-react'
import Navbar from './navbar'
class Back extends Component {
render() {
return (
<div className="wrapper">
<div className="nav"></div>
<div className="main"></div>
</div>
);
}
}
export default Back;
I got just a white screen what might be a problem ?
Thank you
As the wrapper is positioned absolute, and have no content to grow with, its width collapse to 0.
So simply remove position: absolute from the .wrapper, html, body rule.
If you still want to use position: absolute, you need to also give the wrapper a width.
.wrapper,
html,
body {
height: 100%;
margin: 0;
}
.wrapper {
display: flex;
flex-direction: column;
}
.nav {
background-color: red;
flex: 1
}
.main {
background-color: blue;
flex: 1
}
<div class="wrapper">
<div class="nav"></div>
<div class="main"></div>
</div>
You can also use float:left in the wrapper class.

Categories