Como usar o Popover API nativo do browser sem JavaScript

1. O que é a Popover API e por que usar sem JavaScript?

A Popover API é uma funcionalidade nativa do HTML que permite criar elementos flutuantes — como menus, notificações, dicas e painéis — sem precisar escrever uma única linha de JavaScript. Antes dela, desenvolvedores dependiam de bibliotecas como Bootstrap, Popper.js ou implementações manuais com JavaScript para controlar visibilidade, posicionamento e fechamento de popovers.

As vantagens de usar a Popover API sem JavaScript são significativas:

  • Performance: zero overhead de scripts, carregamento instantâneo
  • Acessibilidade: suporte nativo a teclado e leitores de tela
  • Simplicidade: apenas atributos HTML e CSS são necessários
  • Manutenção: menos código para depurar e atualizar

A Popover API difere de outros elementos flutuantes:
- Tooltip: geralmente aparece ao hover, sem interação de clique
- Dialog: requer JavaScript para showModal() e close(), bloqueia interação com o restante da página
- Modal tradicional: implementação complexa com JavaScript para controle de foco e fechamento

2. Atributo popover e o elemento alvo: a base da sintaxe

O coração da Popover API é o atributo popover, que pode receber três valores:

<div popover="auto">   <!-- comportamento padrão, fecha ao clicar fora -->
<div popover="manual"> <!-- permanece aberto até ação explícita -->
<div popover="hint">   <!-- experimental, para dicas temporárias -->

O elemento que será exibido como popover pode ser qualquer elemento HTML — div, section, aside, etc. O importante é que ele tenha o atributo popover e esteja oculto por padrão (o browser gerencia isso automaticamente).

<div id="meu-popover" popover="auto">
  <p>Conteúdo do popover</p>
</div>

3. Controle de abertura e fechamento com atributos HTML

Para controlar o popover, usamos dois atributos no elemento acionador (geralmente um <button>):

  • popovertarget: aponta para o id do popover
  • popovertargetaction: define a ação (toggle, show ou hide)

Exemplo prático — botão que abre e fecha um popover:

<button popovertarget="meu-popover" popovertargetaction="toggle">
  Abrir/Fechar popover
</button>

<div id="meu-popover" popover="auto">
  <p>Este popover foi aberto sem JavaScript!</p>
  <button popovertarget="meu-popover" popovertargetaction="hide">
    Fechar
  </button>
</div>

Com apenas esses atributos, o popover abre ao clicar no botão, fecha ao clicar fora ou pressionar Esc (comportamento auto), e o botão interno também consegue fechá-lo explicitamente.

4. Comportamento auto vs manual: quando usar cada um

A escolha entre auto e manual depende do caso de uso:

Popover auto (padrão):
- Fecha automaticamente ao clicar fora do popover
- Fecha ao pressionar a tecla Esc
- Apenas um popover auto pode estar aberto por vez
- Ideal para: notificações temporárias, menus de navegação, dicas contextuais

<div popover="auto" id="notificacao">
  ✅ Operação concluída com sucesso!
</div>

Popover manual:
- Permanece aberto até receber uma ação explícita de fechamento
- Múltiplos popovers manual podem ficar abertos simultaneamente
- Ideal para: painéis de configuração, formulários embutidos, listas de seleção

<div popover="manual" id="painel-config">
  <h3>Configurações</h3>
  <label><input type="checkbox"> Modo escuro</label>
  <button popovertarget="painel-config" popovertargetaction="hide">Fechar</button>
</div>

5. Estilizando popovers com CSS puro

A Popover API oferece a pseudo-classe :popover-open para estilizar o estado aberto:

<style>
  /* Estado fechado (padrão) */
  #meu-popover {
    padding: 1rem;
    border: 1px solid #ccc;
    border-radius: 8px;
    background: white;
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);

    /* Animação de entrada */
    opacity: 0;
    transform: translateY(-10px);
    transition: opacity 0.3s, transform 0.3s;
  }

  /* Estado aberto */
  #meu-popover:popover-open {
    opacity: 1;
    transform: translateY(0);
  }

  /* Overlay (backdrop) */
  #meu-popover::backdrop {
    background: rgba(0, 0, 0, 0.3);
    backdrop-filter: blur(2px);
  }
</style>

Para posicionamento, você pode usar position: absolute ou position: fixed com top, left, right, bottom. A combinação com CSS Anchor Positioning (tema vizinho) permite posicionamento preciso relativo ao botão acionador.

6. Acessibilidade e semântica embutidas

A Popover API já vem com acessibilidade embutida:

  • Foco automático: ao abrir, o foco vai para o primeiro elemento focável dentro do popover
  • Teclado: Esc fecha popovers auto; Tab navega entre elementos internos
  • ARIA implícito: o browser gerencia automaticamente aria-expanded no botão e role="group" no popover

Para melhorar ainda mais:

<button popovertarget="ajuda" aria-label="Abrir ajuda">
  ?
</button>

<div id="ajuda" popover="auto" role="tooltip" aria-label="Dica de ajuda">
  Pressione Ctrl+S para salvar
</div>

7. Limitações e boas práticas

Navegadores compatíveis: Chrome 114+, Edge 114+, Firefox 125+, Safari 17+. Para fallback em browsers antigos, use um polyfill ou implemente uma versão com JavaScript como alternativa.

Boas práticas:
- Evite aninhar popovers dentro de popovers (pode causar conflitos de foco)
- Use popover="manual" para popovers que contêm formulários ou interações complexas
- Combine com CSS Anchor Positioning para posicionamento preciso sem JavaScript
- Teste com leitores de tela para garantir a experiência de acessibilidade

8. Exemplo completo: um popover funcional apenas com HTML + CSS

<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Popover API sem JavaScript</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      margin: 0;
      background: #f5f5f5;
    }

    .container {
      text-align: center;
    }

    button {
      padding: 12px 24px;
      background: #4CAF50;
      color: white;
      border: none;
      border-radius: 6px;
      cursor: pointer;
      font-size: 16px;
    }

    button:hover {
      background: #45a049;
    }

    #popover-exemplo {
      padding: 20px;
      border: none;
      border-radius: 12px;
      background: white;
      box-shadow: 0 8px 24px rgba(0,0,0,0.2);
      max-width: 300px;

      /* Animação */
      opacity: 0;
      transform: scale(0.9);
      transition: opacity 0.3s, transform 0.3s;
    }

    #popover-exemplo:popover-open {
      opacity: 1;
      transform: scale(1);
    }

    #popover-exemplo::backdrop {
      background: rgba(0, 0, 0, 0.2);
    }

    .popover-content {
      text-align: left;
    }

    .popover-content h3 {
      margin-top: 0;
      color: #333;
    }

    .popover-content p {
      color: #666;
      line-height: 1.5;
    }

    .popover-content button {
      background: #f44336;
      margin-top: 10px;
    }

    .popover-content button:hover {
      background: #da190b;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>Popover API sem JavaScript</h1>
    <p>Clique no botão para abrir o popover</p>

    <button popovertarget="popover-exemplo" popovertargetaction="toggle">
      Abrir Popover
    </button>

    <div id="popover-exemplo" popover="auto">
      <div class="popover-content">
        <h3>Popover Nativo</h3>
        <p>Este popover foi criado apenas com HTML e CSS. 
           Teste: clique fora para fechar, pressione Esc, 
           ou use o botão abaixo.</p>
        <button popovertarget="popover-exemplo" popovertargetaction="hide">
          Fechar
        </button>
      </div>
    </div>
  </div>
</body>
</html>

Teste prático: abra o popover, clique fora para fechar, pressione Esc, navegue com Tab entre os botões. Tudo funciona sem JavaScript.

Referências