A partir do Chrome 135, botões passam a ter `command` e `commandfor`
(developer.chrome.com)- Botões são essenciais para criar aplicações web dinâmicas. Eles são usados para abrir menus, alternar ações e enviar formulários
- No Chrome 135, os novos atributos
commandecommandformelhoram e substituem os antigos atributospopovertargetactionepopovertarget - Problemas que surgiam ao implementar o comportamento de botões até agora:
- O manipulador
onclickdo HTML pode ter uso limitado em código real por causa da política de segurança (CSP) - É necessário sincronizar o estado entre o botão e outros elementos, e o código para gerenciar esse estado mantendo a acessibilidade é complexo
- Em React, AlpineJS, Svelte e outros, o gerenciamento de estado e de eventos também é complexo
- O manipulador
Padrão command e commandfor
- Com os atributos
commandecommandfor, um botão pode agir de forma declarativa sobre outro elemento. Isso oferece a conveniência dos frameworks, mantendo a flexibilidade - O botão com
commandforusa um ID (de forma parecida com o atributofor), ecommandaceita valores embutidos para uma abordagem mais intuitiva - Exemplo: implementação de um botão para abrir menu
- Não é necessário
aria-expandednem JavaScript adicional
<button commandfor="my-menu" command="show-popover"> Open Menu </button> <div popover id="my-menu"> <!-- ... --> </div> - Não é necessário
command e commandfor vs popovertargetaction e popovertarget
- Se você já usou
popover, talvez conheça os atributospopovertargetepopovertargetaction - Eles funcionam de forma semelhante a
commandforecommand, mas são específicos para popover - Os novos atributos substituem completamente os anteriores e oferecem funcionalidades adicionais
Comandos embutidos
- O atributo
commandjá traz embutidos comportamentos mapeados para várias APIsshow-popover: mapeado parael.showPopover()hide-popover: mapeado parael.hidePopover()toggle-popover: mapeado parael.togglePopover()show-modal: mapeado paradialogEl.showModal()close: mapeado paradialogEl.close()
- Exemplo: implementação de um diálogo de confirmação de exclusão
- É possível gerenciar estado e acessibilidade sem JavaScript
<button commandfor="confirm-dialog" command="show-modal"> Delete Record </button> <dialog id="confirm-dialog"> <header> <h1>Delete Record?</h1> <button commandfor="confirm-dialog" command="close" aria-label="Close"> <img role="none" src="/close-icon.svg"> </button> </header> <p>Are you sure? This action cannot be undone</p> <footer> <button commandfor="confirm-dialog" command="close" value="cancel"> Cancel </button> <button commandfor="confirm-dialog" command="close" value="delete"> Delete </button> </footer> </dialog>- Código para tratar o resultado: é possível processar o valor de retorno no evento
closedo diálogo
dialog.addEventListener("close", (event) => { if (event.target.returnValue === "cancel") { console.log("Cancel was clicked"); } else if (event.target.returnValue === "delete") { console.log("Delete was clicked"); } });
Comandos personalizados
- Além dos comandos embutidos, é possível definir comandos personalizados usando o prefixo
-- - Comandos personalizados disparam o evento
"command"no elemento de destino, mas não executam lógica adicional - Exemplo: implementação de um comando para rotacionar imagem
<button commandfor="the-image" command="--rotate-landscape"> Landscape </button> <button commandfor="the-image" command="--rotate-portrait"> Portrait </button> <img id="the-image" src="photo.jpg"> <script type="module"> const image = document.getElementById("the-image"); image.addEventListener("command", (event) => { if (event.command === "--rotate-landscape") { image.style.rotate = "-90deg"; } else if (event.command === "--rotate-portrait") { image.style.rotate = "0deg"; } }); </script>
Tratamento de comandos no Shadow DOM
- No Shadow DOM, como
commandforfunciona com base em ID, existem as seguintes limitações:- Não é possível referenciar elementos entre Shadow DOMs diferentes
- Nesse caso, é possível usar a API JavaScript para definir a propriedade
.commandForElement
- Exemplo: ligação de comando no Shadow DOM
<my-element> <template shadowrootmode="open"> <button command="show-popover">Show popover</button> <slot></slot> </template> <div popover><!-- ... --></div> </my-element> <script> customElements.define("my-element", class extends HTMLElement { connectedCallback() { const popover = this.querySelector('[popover]'); this.shadowRoot.querySelector('button').commandForElement = popover; } }); </script>
Planos futuros
- No Chrome, há planos para adicionar mais comandos embutidos:
- abrir e fechar o elemento <details>
- suporte ao comando
show-pickerem <input> e <select> - comandos de reprodução para <video> e <audio>
- função de copiar texto de elementos
1 comentários
Comentários do Hacker News
Teóricos de linguagens de programação especulam desde os anos 80 sobre
comefrom, uma versão mais poderosa degoto. Isso só foi implementado no INTERCAL. O INTERCAL é superior a linguagens como C em segurança, desempenho e ergonomia, mas tem enfrentado dificuldades para entrar no mercado comercial. É interessante ver o JavaScript incorporando esse recurso do INTERCAL. Espero que isso leve a um aumento da programação educada, assim como os objetos baseados em closures do JavaScript levaram a programação funcional ao mainstreamInvokers não são algo exclusivo do Chrome. Já estão disponíveis também no Firefox Nightly
A ideia de implementar comportamento declarativo de UI sem JS é atraente
aria-expanded)show-modalintegram acessibilidade à marcação--rotate-landscape) permitem que componentes exponham APIs via HTMLDúvidas:
.commandForElemententre shadow roots. Isso parece um problema resolvido só pela metadeshow-picker,toggle-details), a plataforma vai inchar com sintaxe de nicho?Especificação:
button, atributocommandforbutton, atributocommandIsso é o padrão de ação/mensageria que Next, Be, Apple etc. usavam há cerca de 30 anos, ou estou deixando passar alguma coisa?
O antigo toolkit Java de UI da Netscape (IFC) permitia conectar elementos de ação
Os novos atributos
commandecommandformelhoram e substituempopovertargetactionepopovertargetTenho alergia total a programar com strings. Entendo os benefícios de acessibilidade, mas não me anima particularmente usar IDs de elementos como mais uma camada de comportamento de app web
Não deveriam ter implementado isso sem a API completa. Em vez de uns 5 comandos, parece que seria possível implementar toda a funcionalidade de JavaScript via HTML. Isso daria milhares de comandos
Eu estava esperando algo sobre command and conquer em HTML
Melhorar e expandir o HTML é bom, mas ainda há um longo caminho pela frente. O pessoal do HTMX tem algumas boas ideias