Portais para modais e dicas de contexto
Utilizar ReactDOM.createPortal para renderizar filhos num nó DOM diferente, permitindo criar modais e dicas de contexto que escapam a contentores com overflow:hidden.
Portais para modais e dicas de contexto é uma aula grátis de Frontend Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Frontend Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Frontend Academy inclui 4 aulas no total.
O problema de escapar do contêiner
Modais e dicas de ferramenta precisam ser renderizados no topo do DOM, escapando de overflow:hidden, do empilhamento de z-index e dos contextos baseados em transform do componente pai. A solução são os portais.
API createPortal
createPortal(children, container) renderiza children dentro de container (qualquer nó do DOM), mantendo-os logicamente como filhos do componente React para eventos e contexto.
import { createPortal } from 'react-dom';
function Modal({ children, onClose }) {
return createPortal(
<div className="modal-backdrop" onClick={onClose}>
<div className="modal-content" onClick={e => e.stopPropagation()}>
{children}
</div>
</div>,
document.body
);
}Contêineres de portais
Destinos comuns: document.body, uma div #modal-root dedicada em index.html ou um contêiner referenciado por ref, criado sob demanda.
<!-- index.html -->
<div id="root"></div>
<div id="modal-root"></div>
// component:
const modalRoot = document.getElementById('modal-root');
return createPortal(<div>...</div>, modalRoot);Por que não renderizar diretamente
Se um componente pai tiver overflow: hidden, um modal filho será recortado. Se um componente pai tiver transform: scale, o posicionamento fixo do modal ficará relativo ao componente pai. Os portais evitam tudo isso.
Os eventos ainda fazem propagação
Apesar de serem renderizados em outro lugar do DOM, os eventos do React fazem propagação pela árvore de componentes, não pela árvore do DOM. Um clique no portal ainda chega aos manipuladores onClick dos componentes React ancestrais.
Fechamento ao clicar na sobreposição
Interrompa a propagação de eventos no conteúdo do modal para que os cliques internos não fechem o modal.
function Modal({ onClose, children }) {
return createPortal(
<div className="backdrop" onClick={onClose}>
<div className="content" onClick={e => e.stopPropagation()}>
{children}
</div>
</div>,
document.body
);
}Fechamento com a tecla Escape
Adicione um ouvinte de keydown enquanto o modal estiver aberto e remova-o durante a desmontagem.
useEffect(() => {
const onKey = (e) => { if (e.key === 'Escape') onClose(); };
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
}, [onClose]);Gerenciamento de foco em portais
Quando um modal for aberto: mova o foco para dentro dele, mantenha o foco preso até o fechamento e depois restaure o foco ao elemento que abriu o modal. Use uma biblioteca como focus-trap-react para evitar reimplementar isso.
Elemento dialog nativo
O <dialog> do HTML trata nativamente do posicionamento do modal, do plano de fundo, da retenção de foco e do fechamento com Escape. Para a maioria dos modais, ele é um ponto de partida melhor do que um portal.
function Modal({ open, onClose, children }) {
const ref = useRef(null);
useEffect(() => {
if (open) ref.current?.showModal();
else ref.current?.close();
}, [open]);
return (
<dialog ref={ref} onClose={onClose}>
{children}
</dialog>
);
}Dicas de ferramenta e popovers
Dicas de ferramenta são posicionadas em relação a um elemento âncora. Um portal permite que elas escapem dos contextos de empilhamento. Combine-o com floating-ui para detecção de colisões, inversão e posicionamento.
import { useFloating, autoUpdate } from '@floating-ui/react';
function Tooltip({ children, content }) {
const { refs, floatingStyles } = useFloating({ whileElementsMounted: autoUpdate });
const [open, setOpen] = useState(false);
return (
<>
<button ref={refs.setReference} onMouseEnter={() => setOpen(true)} onMouseLeave={() => setOpen(false)}>
{children}
</button>
{open && createPortal(
<div ref={refs.setFloating} style={floatingStyles}>{content}</div>,
document.body
)}
</>
);
}ressalva sobre SSR
document não existe no servidor. Renderize apenas no cliente (verifique typeof window) ou use o recurso dynamic do Next.js com ssr:false.
Acessibilidade: aria-modal
Os contêineres de modais devem ter role="dialog", aria-modal="true" e aria-labelledby apontando para o título do modal. Ou use o
Verificação rápida
Por que usar createPortal para modais em vez de renderizá-los diretamente na árvore de componentes?
Recapitulação: portais
createPortal(children, container) renderiza o DOM em outro local, mantendo a árvore lógica do React. Resolve problemas de escape relacionados a overflow, transform e z-index. Os eventos ainda fazem propagação pela árvore do React. Adicione o fechamento com Escape e o gerenciamento de foco. O
Perguntas Frequentes
A aula “Portais para modais e dicas de contexto” é grátis?
Sim — o texto completo de “Portais para modais e dicas de contexto” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Frontend Academy, atualize para CoddyKit PRO. O curso de Frontend Academy inclui 4 aulas no total.
O que vou aprender em “Portais para modais e dicas de contexto”?
Utilizar ReactDOM.createPortal para renderizar filhos num nó DOM diferente, permitindo criar modais e dicas de contexto que escapam a contentores com overflow:hidden. Você pratica Frontend Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Frontend Academy?
Nenhuma experiência prévia é necessária. Frontend Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Portais para modais e dicas de contexto”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Frontend Academy?
Sim. Cada aula de Frontend Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Componentes compostos com Context
- Propriedades de renderização e padrões HOC
- Portais para modais e dicas de contexto
- Limites de erros