I have a component that blurs everything that is on the screen.
const SVGBlur = () => (
<svg style={{position: 'absolute', top: '-99999px'}} xmlns="http://www.w3.org/2000/svg">
<filter id="svgBlur" x="-5%" y="-5%" width="150%" height="150%">
<feGaussianBlur in="SourceGraphic" stdDeviation={5}/>
</filter>
</svg>
)
const BlurOverlay = ({children}) => {
const [domNode, setDomNode] = useState(null);
useEffect(() => {
const blurContainer = document.createElement('div')
const childrenContainer = document.getElementById('root')
const elementToApplyBlurTo = document.getElementById('blur-overlay')
if (elementToApplyBlurTo && childrenContainer) {
childrenContainer.appendChild(blurContainer)
elementToApplyBlurTo.setAttribute('style', 'filter: url(#svgBlur); filter: blur(5px);')
setDomNode(childrenContainer)
}
return () => {
if (elementToApplyBlurTo && childrenContainer) {
childrenContainer.removeChild(blurContainer)
elementToApplyBlurTo.setAttribute('style', '')
}
}
}, [])
return domNode && ReactDOM.createPortal(
<>
{children}
<SVGBlur />
</>,
domNode,
)
}
export default BlurOverlay;
I want to be able to blurr everything and at the same time insert children that are on top of all the blurred stuff. Basically like a Modal on the backdrop. However, the children I am passing BlurOverlay
are always blurred too, because they appear as children of root
, but after the <div/>
with id=blur-overlay
;
This is the DOM before <BlurOverlay />
<div id='root'>
<div className="App" id={'blur-overlay'}>
...
</div>
</div>
And this is the order after creating the Portal
<div id='root'>
<div className="App" id={'blur-overlay'}> <- BLUR STYLES APPLIED
...
<div>THIS CONTAINS THE CHILDREN PASSED TO <BlurOverlay></div>
<svg .../>
</div>
</div>
In order for the children not to be blurred, they need to be here
<div id='root'>
<div>THIS CONTAINS THE CHILDREN PASSED TO <BlurOverlay></div>
<div className="App" id={'blur-overlay'}> <- BLUR STYLES APPLIED
...
<svg .../>
</div>
</div>
How to achieve that?