2 pontos por GN⁺ 2024-05-11 | 1 comentários | Compartilhar no WhatsApp
  • Com apenas recursos nativos do navegador, é possível criar uma UI de popover que aparece sobre a página, permitindo implementar padrões como menus, sugestões e notificações de forma mais consistente
  • Os popovers da Popover API são sempre não modais, portanto `` é mais adequado para UIs que precisam bloquear a interação com a página
  • Alternâncias simples podem ser feitas com atributos HTML como popover, popovertarget e popovertargetaction, e, quando necessário, o estado de exibição pode ser controlado com métodos JavaScript
  • É possível lidar com estilo e mudanças de estado com ::backdrop, :popover-open, beforetoggle, toggle etc., e os interest invokers oferecem suporte à exibição por hover/focus sem JavaScript
  • É um recurso Baseline 2025 que funciona em dispositivos e navegadores atuais desde janeiro de 2025, mas vale verificar a compatibilidade em ambientes antigos ou em alguns recursos mais específicos

O problema que a Popover API resolve

  • A Popover API fornece um mecanismo padrão para exibir conteúdo de popover sobre outro conteúdo da página
  • Os popovers podem ser controlados apenas com atributos HTML ou com a API JavaScript para manipular diretamente os estados de exibição e ocultação
  • Padrões de UI que na web eram chamados de overlays, popups, popovers e dialogs podem ser implementados de forma mais consistente com recursos nativos do navegador

Se você precisa de modal, use ``

  • As UIs de popover se dividem, em geral, entre modais e não modais
    • Em modais, não é possível interagir com o restante da página enquanto o popover estiver visível
    • Em não modais, é possível continuar interagindo com o restante da página mesmo com o popover aberto
  • Os popovers criados com a Popover API são sempre não modais
  • Se você precisa de um popover modal que bloqueie a interação com a página, o elemento `` é o mais indicado
  • Uma abordagem como aplicar `popover` em também é válida, permitindo usar ao mesmo tempo o controle de popover e a semântica de dialog

Forma básica de uso

  • A Popover API pode ser usada com frequência em UIs que exigem interação do usuário
    • menus de ação
    • notificações toast personalizadas
    • sugestões para elementos de formulário
    • seletores de conteúdo
    • interfaces educacionais
  • É possível criar um botão simples para alternar um popover apenas com HTML
Toggle the popover
Popover content

  • Em JavaScript, HTMLElement.togglePopover() alterna o estado de exibição/ocultação do popover
  • A API também oferece eventos para reagir a mudanças de estado do popover e recursos de CSS para facilitar a estilização

Atributos HTML

  • interestfor
    • Define elementos HTML , e ou o elemento SVG como interest invoker
    • O valor é o id do elemento de destino, e esse elemento é afetado quando o interest aparece ou desaparece no elemento invoker
  • popover
    • É um atributo global que transforma um elemento em um elemento popover
    • Pode receber os estados "auto", "hint" e "manual"
  • popovertarget
    • Transforma um elemento ou em um botão de controle de popover
    • O valor é o ID do elemento popover a ser controlado
  • popovertargetaction
    • Define a ação que o botão de controle executará no popover
    • Os valores possíveis são "hide", "show" e "toggle"

Estados de exibição via CSS

  • ::backdrop
    • É um pseudoelemento de tela cheia posicionado logo atrás do elemento popover
    • Se necessário, ele pode aplicar efeitos como desfoque ao conteúdo da página atrás do popover
  • interest-delay, interest-delay-start, interest-delay-end
    • Adicionam um tempo de espera entre o momento em que o usuário demonstra ou perde interest e o momento em que o navegador reage
  • :interest-source, :interest-target
    • Permitem aplicar estilos, respectivamente, ao invoker e ao elemento de destino associado quando o interest estiver ativo
  • :popover-open
    • É uma pseudoclasse que só corresponde quando o elemento popover está visível
    • É usada para estilizar o popover em estado aberto

Interface JavaScript e extensões do DOM

  • InterestEvent
    • É o objeto de evento dos eventos interest e loseinterest
    • Inclui a propriedade source, que contém uma referência ao elemento interest invoker associado
  • ToggleEvent
    • Representa o evento disparado quando o elemento popover alterna entre os estados visível e oculto
    • É o objeto de evento dos eventos beforetoggle e toggle
  • interestForElement
    • Obtém ou define a referência do elemento que um interest invoker usa como alvo
    • Pode ser usado em HTMLButtonElement, HTMLAnchorElement, HTMLAreaElement e SVGAElement
  • HTMLElement.popover
    • Obtém ou define via JavaScript o estado de popover de um elemento
    • Usa os valores "auto", "hint" e "manual", e também pode ser usado para detecção de recurso
    • Reflete o valor do atributo global HTML popover
  • popoverTargetElement
    • Em HTMLButtonElement e HTMLInputElement, obtém ou define o elemento popover controlado pelo botão
    • É o equivalente em JavaScript do atributo HTML popovertarget
  • popoverTargetAction
    • Em HTMLButtonElement e HTMLInputElement, obtém ou define a ação de popover a ser executada
    • Usa os valores "hide", "show" e "toggle" e reflete o atributo popovertargetaction

Métodos e eventos

  • HTMLElement.hidePopover()
    • Remove o elemento popover da top layer e o oculta aplicando estilo display: none
  • HTMLElement.showPopover()
    • Adiciona o elemento popover à top layer para exibição
  • HTMLElement.togglePopover()
    • Alterna o elemento popover entre os estados visível e oculto
  • beforetoggle
    • É disparado imediatamente antes de o estado do elemento popover mudar entre visível e oculto
    • Pode ser usado para impedir a abertura do popover ou atualizar outros elementos de acordo com o estado do popover
  • toggle
    • É disparado logo após a mudança de estado do popover
  • interest
    • É disparado no elemento de destino do interest invoker quando o interest é mostrado
  • loseinterest
    • É disparado no elemento de destino do interest invoker quando o interest desaparece

Exemplos e links de especificação

1 comentários

 
GN⁺ 2024-05-11
Opiniões no Hacker News
  • A Popover API parece que vai provocar uma mudança realmente grande quando chegar também o posicionamento por âncora em CSS (CSS Anchor Positioning)
    O posicionamento por âncora permite posicionar um elemento com base em outro elemento da página
    Combinado com a Popover API, dá para implementar tooltips personalizados ou menus de contexto de forma declarativa, sem precisar de bibliotecas como PopperJS
    https://developer.chrome.com/blog/tether-elements-to-each-ot...
    https://popper.js.org/docs/v2/

    • Acabei de publicar um novo artigo sobre como usar a CSS Anchor API, que deve entrar no Chromium na próxima semana
      https://developer.chrome.com/blog/anchor-positioning-api
    • O status de suporte dos navegadores pode ser visto aqui
      https://caniuse.com/css-anchor-positioning
    • Se o posicionamento por âncora em CSS existisse nos últimos anos, eu teria economizado uma quantidade enorme de tempo
    • Esta é a peça essencial que faltava
      Na semana passada tentei criar e lançar algo com a nova Popover API, mas a falta de suporte a posicionamento em todos os navegadores limitou bastante os casos de uso
      Como o último navegador, o Firefox, parece já ter incluído posicionamento por âncora no beta, acho que não deve demorar muito
    • É surpreendente que, em 2024, HTML/CSS ainda não tenha um atributo de tooltip como title
  • Se você precisa de uma caixa de diálogo modal, também existe o elemento <dialog>
    https://developer.mozilla.org/en-US/docs/Web/HTML/Element/di...

    • Se você precisa de conteúdo expansível/recolhível, ou até, forçando um pouco, de um “dropdown”, também pode usar <details>
      Curiosamente, ao contrário de <dialog> ou <details>, parece que <popover> não consegue criar declarativamente o estado open apenas com um atributo
      Parece uma funcionalidade ausente, e espero que tenha havido uma justificativa para essa decisão
      https://developer.mozilla.org/en-US/docs/Web/HTML/Element/de...
    • Vale avisar que dá bastante trabalho levar as animações e o comportamento modal comum ao nível esperado hoje em dia
      É totalmente possível, mas está longe de ser algo trivial
    • Como foi apontado, animações são mais difíceis, mas ele já vem com acessibilidade, fechamento pela tecla Esc, backdrop embutido e focus trap embutido
      O suporte no Safari demorou, mas agora dá para usar em qualquer lugar
      Acho melhor do que montar tags manualmente
    • Isso já é abordado nos primeiros parágrafos do artigo
  • Se for implementado em conjunto com o sistema de janelas do sistema operacional hospedeiro, esse recurso parece claramente necessário
    Porque hoje popovers precisam ser imitados de um jeito que nem sempre funciona bem
    Por exemplo, um <select> nativo do navegador pode se estender para além dos limites da janela do navegador, então não é preciso se preocupar em ele ser cortado pela janela; já selects falsos e sofisticados de toolkits como Quasar não conseguem fazer isso, o que limita as opções de posicionamento
    Para fazer direito, no win32 cada popover provavelmente teria que ter seu próprio HWND nativo e, no Cocoa/macOS, ficar dentro de sua própria NSView
    Fico curioso se os navegadores hoje realmente implementam assim, ou se apenas desenham por cima dentro da janela do navegador

    • Esses popovers são simplesmente nós DOM comuns e são estilizados com CSS comum
      Se você permitir que sites desenhem fora do viewport designado, fica muito mais fácil imitar de forma convincente diálogos do navegador ou do sistema operacional, exceto em casos extremamente limitados como alert(), confirm() e [title]
      Por exemplo, uma página poderia imitar o widget de desbloqueio de uma extensão de gerenciador de senhas
      Isso é um grande risco de segurança e, na minha opinião, não vale a pena diante dos benefícios limitados
      Essa não é uma preocupação teórica
      Golpistas vêm criando há anos interfaces falsas muito convincentes, incluindo janelas popup falsas com até a chrome do navegador, e até arrastáveis
      A impossibilidade de desenhar para fora dos limites do viewport era praticamente a única restrição que eles ainda não tinham conseguido contornar
    • Não sei o quão útil esse recurso seria na prática
      Em dispositivos pequenos, o navegador quase sempre ocupa a tela inteira; mesmo em monitores grandes, normalmente ele encosta em pelo menos um dos cantos
    • Acho que também ficaria mais fácil detectar isso semanticamente
      O mesmo vale para acessibilidade e capacidade de ser rastreado, e também seria útil se alguém quisesse criar um plugin de “bloquear popups”
    • O Firefox tecnicamente suporta fazer parte do conteúdo da página “saltar” para uma janela em nível de sistema operacional separada
      Esse recurso é exposto por meio de elementos XUL que só podem ser usados em [X]HTML privilegiado renderizado no processo principal do navegador
      Acho que nenhum desenvolvedor de navegador gostaria de dar a páginas web comuns permissão para criar janelas do sistema operacional sem borda
    • Não parece que web apps vão obter tão cedo a integração com sistema de janelas nativo que você imaginou
      O fato de alguns controles padrão se comportarem assim é um efeito colateral de implementação específico de cada sistema operacional, por terem sido implementados nativamente no OS, e não algo que necessariamente precise ser implementado dessa forma
  • É meio engraçado que os navegadores tenham bloqueadores de pop-up embutidos e, ainda assim, criem uma API dessas
    Sei que há uma diferença, mas mesmo assim
    Já tenho idade suficiente para lembrar das guerras de pop-ups/pop-unders do fim dos anos 90 e começo dos anos 2000
    Acho que vencemos aquela batalha, mas a guerra pela nossa atenção ainda está longe de acabar

    • Parece que estão comparando coisas diferentes
      Um popover é um elemento flutuante que mostra informações de contexto quando necessário
      O que você mencionou é algo completamente diferente
    • Entendo o ponto, mas na prática acho que não é uma comparação válida
      Pop-ups espalhavam janelas lixo pelo sistema operacional e, no pior caso, atrapalhavam o próprio uso do computador
      Um diálogo popover acaba quando você fecha a aba
      Esse estilo de popover é bem útil para mostrar informações e já é usado há muito tempo
      Pode ser usado de forma irritante, mas, assim como modais, também tem muitos casos de uso reais
    • Vejo muita reação desse tipo, mas ela não faz muito sentido
      Hoje já dá para implementar popovers com div e coisas do tipo
      Ex.: https://getbootstrap.com/docs/5.3/components/popovers/
      O que muda é que será possível implementar popovers sem uma biblioteca adicional mágica
      Mesmo que bloqueassem um elemento explícito “popover”, as pessoas continuariam usando bibliotecas customizadas
    • Isso não é um pop-up
      As pessoas odeiam pop-ups porque são intrusivos e têm uma janela separada
      Esta API substitui modais em div e reduz o tempo e o código dos desenvolvedores
    • A implementação original de pop-ups quebra a fronteira entre o conteúdo da aplicação e o sistema operacional, e os bloqueadores de pop-up existem para impedir isso
      Esta API não quebra essa fronteira
      Quando essa fronteira é quebrada, a usabilidade e a segurança do sistema pioram, então é uma direção indesejada
  • Dizem que “popovers criados com a Popover API são sempre não modais. Se quiser criar um popover modal, o elemento <dialog> é o correto”, mas não entendo por quê
    Esse é um caso de uso legítimo para popovers
    Especialmente se o fundo ficar desfocado quando aberto; se um botão desfocado puder ser acionado por um clique acidental do usuário, fico me perguntando por que esse recurso é oferecido
    Pelo que encontrei, dá para combinar os dois
    Algo como “se quiser combinar controle de popover com semântica de diálogo, você pode transformar um elemento <dialog> em popover”
    Então acho que aqui faria mais sentido ter um atributo como modal
    Já que o caso de uso é claramente reconhecido

    • Talvez um dos motivos seja que o <dialog> já existia bem antes
  • Muito bom
    Se entendi direito, em vez de introduzir uma funcionalidade nova, parece simplificar algo que antes exigia div modal, div de máscara, div contêiner e CSS incômodo de posicionamento
    Também foram adicionadas pseudoclasses que facilitam a estilização, gostei

    • Também permite usar a funcionalidade básica sem JavaScript
      Sem precisar forçar o uso de um checkbox escondido
      Não sei até onde dá para ir sem JS com popovers estilizados e animados, mas suporte sem JS com tratamento correto de foco é bom
      Eu gostaria de dizer que o suporte a acessibilidade também vem embutido, mas não consegui encontrar isso na especificação atual
      Se também cuidar de informar o elemento a ferramentas de acessibilidade, como leitores de tela, será uma grande ajuda
      Porque, ao fazer isso manualmente, é bem fácil esquecer algo
    • Esta API permite controlar, no DOM, o estado de exibição do elemento popover mesmo sem JavaScript
      É definitivamente útil
  • Demo: https://mdn.github.io/dom-examples/popover-api

    • Na demo de popovers aninhados, não dá para mover em diagonal de Pizza para Ham
      Porque ninguém no Chrome ou no Firefox implementou o atraso antes de o submenu desaparecer
      Décadas de pesquisa em experiência do usuário desapareceram e, de certa forma, era quase o esperado
      https://mdn.github.io/dom-examples/popover-api/nested-popove...
    • Pela tabela de suporte dos navegadores, deveria funcionar, mas parece que não funciona no iOS Safari
  • Parece legal, mas não entendo por que esta página não tem nenhuma imagem mostrando o que é um popover

  • Excelente
    Aqui está uma implementação customizada feita com Stimulus usando Popper
    https://github.com/tramlinehq/tramline/blob/main/app/javascr...
    E aqui está a implementação para diálogos
    https://github.com/tramlinehq/tramline/blob/main/app/javascr...