https://developer.chrome.com/blog/command-and-commandfor Skip to main content Chrome for Developers * Get inspired Blog Docs * Build with Chrome * Learn how Chrome works, participate in origin trials, and build with Chrome everywhere. * Web Platform * Capabilities * ChromeDriver * Extensions * Chrome Web Store * Chromium * Aurora * Web on Android * Origin trials * Release notes * Productivity * Create the best experience for your users with the web's best tools. * DevTools * Lighthouse * Chrome UX Report * Accessibility * Get things done quicker and neater, with our ready-made libraries. * Workbox * Puppeteer * Experience * Design a beautiful and performant web with Chrome. * AI * Performance * CSS and UI * Identity * Payments * Privacy and security * Resources * More from Chrome and Google. * All documentation * Baseline * web.dev * PageSpeed Insights audit * The Privacy Sandbox New in Chrome [ ] / * English * Deutsch * Espanol - America Latina * Francais * Indonesia * Italiano * Nederlands * Polski * Portugues - Brasil * Tieng Viet * Turkce * Russkii * `bryt * l`rbyW@ * frsy * hiNdii * baaNlaa * phaasaaaithy * Zhong Wen - Jian Ti * Zhong Wen - Fan Ti * Ri Ben Yu * hangugeo Sign in * Blog [ ] Chrome for Developers * * Get inspired * Blog * Docs + More * New in Chrome * Build with Chrome * Web Platform * Capabilities * ChromeDriver * Extensions * Chrome Web Store * Chromium * Aurora * Web on Android * Origin trials * Release notes * Productivity * DevTools * Lighthouse * Chrome UX Report * Accessibility * Workbox * Puppeteer * Experience * AI * Performance * CSS and UI * Identity * Payments * Privacy and security * Resources * All documentation * Baseline * web.dev * PageSpeed Insights audit * The Privacy Sandbox * Chrome for Developers * Blog Introducing command and commandfor Stay organized with collections Save and categorize content based on your preferences. Keith Cirkel Keith Cirkel Published: March 7, 2025 Buttons are essential to making dynamic web applications. Buttons open menus, toggle actions, and submit forms. They provide the foundation of interactivity on the web. Making buttons simple and accessible can lead to some surprising challenges. Developers building micro-frontends or component systems can encounter solutions that become more complex than necessary. While frameworks help, the web can do more here. Chrome 135 introduces new capabilities for providing declarative behaviour with the new command and commandfor attributes, enhancing and replacing the popovertargetaction and popovertarget attributes. These new attributes can be added to buttons, letting the browser address some core issues around simplicity and accessibility, and provide built-in common functionality. Traditional patterns Building button behaviours without a framework can pose some interesting challenges as production code evolves. While HTML offers onclick handlers to buttons, these are often disallowed outside of demos or tutorials due to Content Security Policy (CSP) rules. While these events are dispatched on button elements, buttons are usually placed on a page to control other elements requiring code to control two elements at once. You also need to ensure this interaction is accessible to users of assistive technology. This often leads to code looking a bit like this: This approach can be a little brittle, and frameworks aim to improve ergonomics. A common pattern with a framework like React might involve mapping the click to a state change: function MyMenu({ children }) { const [isOpen, setIsOpen] = useState(false); const open = useCallback(() => setIsOpen(true), []); const handleToggle = useCallback((e) => { // popovers have light dismiss which influences our state setIsOpen(e.newState === 'open') }, []); const popoverRef = useRef(null); useEffect(() => { if (popoverRef.current) { if (isOpen) { popoverRef.current.showPopover(); } else { popoverRef.current.hidePopover(); } } }, [popoverRef, isOpen]); return ( <>
{children}
); } Many other frameworks also aim to provide similar ergonomics, for example this might be written in AlpineJS as:
While writing this in Svelte might look something like:
Some design systems or libraries might go a step further, by providing wrappers around button elements that encapsulate the state changes. This abstracts state changes behind a trigger component, trading a little flexibility for improved ergonomics: import {MenuTrigger, MenuContent} from 'my-design-system'; function MyMenu({children}) { return ( {children} ); } The command and commandfor pattern With the command and commandfor attributes, buttons can now perform actions on other elements declaratively, bringing the ergonomics of a framework without sacrificing flexibility. The commandfor button takes an ID--similar to the for attribute--while command accepts built-in values, enabling a more portable and intuitive approach. Example: An open menu button with command and commandfor The following HTML sets up declarative relationships between the button and the menu which lets the browser handle the logic and accessibility for you. There's no need to manage aria-expanded or add any additional JavaScript.
Comparing command and commandfor with popovertargetaction and popovertarget If you've used popover before, you might be familiar with the popovertarget and popovertargetaction attributes. These work similarly to commandfor and command respectively--except they're specific to popovers. The command and commandfor attributes completely replace these older attributes. The new attributes support everything the older attributes did, as well as adding new capabilities. Built-in commands The command attribute has a set of built-in behaviours which map to various APIs for interactive elements: * show-popover: Maps to el.showPopover(). * hide-popover: Maps to el.hidePopover(). * toggle-popover: Maps to el.togglePopover(). * show-modal: Maps to dialogEl.showModal(). * close: Maps to dialogEl.close(). These commands map to their JavaScript counterparts, while also streamlining accessibility (such as providing the aria-details and aria-expanded equivalent relations), focus management, and more. Example: A confirmation dialog with command and commandfor

Delete Record?

Are you sure? This action cannot be undone

Clicking the Delete Record button will open the dialog as a modal, while clicking the Close, Cancel, or Delete buttons will close the dialog while also dispatching a "close" event on the dialog, which has a returnValue property matching the button's value. This reduces the need for JavaScript beyond a single event listener on the dialog to determine what to do next: dialog.addEventListener("close", (event) => { if (event.target.returnValue == "cancel") { console.log("cancel was clicked"); } else if (event.target.returnValue == "close") { console.log("close was clicked"); } else if (event.target.returnValue == "delete") { console.log("delete was clicked"); } }); Custom commands In addition to the built-in commands, you can define custom commands using a -- prefix. Custom commands will dispatch a "command" event on the target element (just like the built-in commands), but otherwise will never perform any additional logic like the built-in values do. This gives flexibility for building components that can react to buttons in various ways without having to provide wrapper components, traverse the DOM for the target element, or mapping button clicks to state changes. This lets you provide an API within HTML for your components: Commands in the ShadowDOM Given the commandfor attribute takes an ID, there are restrictions around crossing the shadow DOM. In these cases you can use the JavaScript API to set the .commandForElement property which can set any element, across shadow roots:
Future proposals may provide a declarative way to share references across shadow boundaries, such as the Reference Target Proposal. What's next? We'll be continuing to explore possibilities for new built-in commands, to cover common functionality that websites use. Proposed ideas are covered in the Open UI Proposal. Some of the ideas already explored: * Opening and closing
elements. * A "show-picker" command for and