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.