Global Attribute
NEW
The popovertarget attribute connects a button to a popover element, allowing the button to control (show, hide, or toggle) the popover. It provides a declarative way to create interactive UI without requiring JavaScript.
< button popovertarget = " popover-id " > Open Popover </ button >
< div id = " popover-id " popover > Popover content </ div >
Value Description ID string The id of the popover element to control
Interactive code playground requires JavaScript. Here's the code:
<!DOCTYPE html>
<html>
<head>
<style>
body { padding: 40px; font-family: Arial, sans-serif; }
.trigger-btn {
padding: 12px 24px;
background: #3b82f6;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
font-weight: 600;
}
.trigger-btn:hover { background: #2563eb; }
.my-popover {
padding: 24px;
border: 2px solid #3b82f6;
border-radius: 12px;
background: white;
box-shadow: 0 10px 40px rgba(0,0,0,0.15);
max-width: 300px;
}
.my-popover h3 {
margin: 0 0 12px;
color: #1e293b;
}
.my-popover p {
margin: 0;
color: #64748b;
line-height: 1.6;
}
</style>
</head>
<body>
<h2>popovertarget Example</h2>
<p>Click the button to toggle the popover:</p>
<!-- Button controls the popover -->
<button class="trigger-btn" popovertarget="info-popover">
Toggle Info
</button>
<!-- Popover controlled by button -->
<div id="info-popover" popover class="my-popover">
<h3>Information</h3>
<p>This popover is controlled by the button above using the popovertarget attribute.</p>
<p style="margin-top: 10px;">Click the button again or click outside to close.</p>
</div>
</body>
</html>
Interactive code playground requires JavaScript. Here's the code:
<!DOCTYPE html>
<html>
<head>
<style>
.demo { padding: 30px; font-family: Arial, sans-serif; }
.button-group {
display: flex;
gap: 10px;
flex-wrap: wrap;
margin: 20px 0;
}
button {
padding: 10px 20px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 600;
transition: transform 0.2s;
}
button:hover { transform: translateY(-2px); }
.btn-show {
background: #10b981;
color: white;
}
.btn-hide {
background: #ef4444;
color: white;
}
.btn-toggle {
background: #3b82f6;
color: white;
}
#settings-popover {
padding: 24px;
border: 2px solid #e2e8f0;
border-radius: 12px;
background: white;
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
max-width: 350px;
}
#settings-popover h3 {
margin: 0 0 15px;
color: #1e293b;
}
.setting-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid #f1f5f9;
}
.setting-item:last-child {
border-bottom: none;
}
</style>
</head>
<body>
<div class="demo">
<h2>Multiple Control Buttons</h2>
<p>Different buttons can control the same popover:</p>
<div class="button-group">
<button
class="btn-show"
popovertarget="settings-popover"
popovertargetaction="show">
Show Settings
</button>
<button
class="btn-hide"
popovertarget="settings-popover"
popovertargetaction="hide">
Hide Settings
</button>
<button
class="btn-toggle"
popovertarget="settings-popover">
Toggle Settings
</button>
</div>
<div id="settings-popover" popover>
<h3>⚙️ Settings</h3>
<div class="setting-item">
<span>Notifications</span>
<input type="checkbox" checked>
</div>
<div class="setting-item">
<span>Dark Mode</span>
<input type="checkbox">
</div>
<div class="setting-item">
<span>Auto-save</span>
<input type="checkbox" checked>
</div>
</div>
</div>
</body>
</html>
Interactive code playground requires JavaScript. Here's the code:
<!DOCTYPE html>
<html>
<head>
<style>
body { padding: 40px; font-family: Arial, sans-serif; }
button {
padding: 10px 20px;
background: #3b82f6;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
margin: 5px;
}
button:hover { background: #2563eb; }
[popover] {
padding: 20px;
border: 2px solid #e2e8f0;
border-radius: 8px;
background: white;
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
}
#main-menu {
min-width: 200px;
}
#submenu {
border-color: #8b5cf6;
min-width: 180px;
}
.menu-item {
padding: 10px;
cursor: pointer;
border-radius: 4px;
margin: 5px 0;
}
.menu-item:hover {
background: #f1f5f9;
}
</style>
</head>
<body>
<h2>Nested Popovers</h2>
<p>Popovers can be nested inside each other:</p>
<button popovertarget="main-menu">Open Menu</button>
<div id="main-menu" popover>
<h3 style="margin-top: 0;">Main Menu</h3>
<div class="menu-item">File</div>
<div class="menu-item">Edit</div>
<div class="menu-item">
<button popovertarget="submenu">View ▶</button>
</div>
<div class="menu-item">Help</div>
<!-- Nested popover -->
<div id="submenu" popover>
<h4 style="margin-top: 0;">View Options</h4>
<div class="menu-item">Zoom In</div>
<div class="menu-item">Zoom Out</div>
<div class="menu-item">Full Screen</div>
</div>
</div>
</body>
</html>
Interactive code playground requires JavaScript. Here's the code:
<!DOCTYPE html>
<html>
<head>
<style>
body { padding: 40px; font-family: Arial, sans-serif; }
.open-btn {
padding: 14px 28px;
background: #3b82f6;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
font-weight: 600;
}
.open-btn:hover { background: #2563eb; }
.dialog-popover {
padding: 0;
border: none;
border-radius: 16px;
background: white;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
max-width: 450px;
width: 90%;
}
.dialog-popover::backdrop {
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(2px);
}
.dialog-header {
background: #3b82f6;
color: white;
padding: 20px;
border-radius: 16px 16px 0 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.dialog-header h3 {
margin: 0;
}
.close-btn {
background: rgba(255, 255, 255, 0.2);
border: none;
color: white;
width: 32px;
height: 32px;
border-radius: 50%;
cursor: pointer;
font-size: 20px;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
}
.close-btn:hover {
background: rgba(255, 255, 255, 0.3);
}
.dialog-content {
padding: 24px;
}
.dialog-actions {
padding: 20px;
border-top: 1px solid #e2e8f0;
display: flex;
gap: 10px;
justify-content: flex-end;
}
.dialog-actions button {
padding: 10px 20px;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
}
.btn-cancel {
background: #e2e8f0;
color: #1e293b;
}
.btn-confirm {
background: #3b82f6;
color: white;
}
</style>
</head>
<body>
<h2>Dialog with Close Button</h2>
<button class="open-btn" popovertarget="confirm-dialog">
Delete Item
</button>
<div id="confirm-dialog" popover="manual" class="dialog-popover">
<div class="dialog-header">
<h3>Confirm Delete</h3>
<button
class="close-btn"
popovertarget="confirm-dialog"
popovertargetaction="hide"
aria-label="Close">
×
</button>
</div>
<div class="dialog-content">
<p>Are you sure you want to delete this item?</p>
<p style="color: #64748b; font-size: 14px;">This action cannot be undone.</p>
</div>
<div class="dialog-actions">
<button class="btn-cancel" popovertarget="confirm-dialog" popovertargetaction="hide">
Cancel
</button>
<button class="btn-confirm" onclick="alert('Item deleted!'); document.getElementById('confirm-dialog').hidePopover();">
Delete
</button>
</div>
</div>
</body>
</html>
Interactive code playground requires JavaScript. Here's the code:
<!DOCTYPE html>
<html>
<head>
<style>
body { padding: 40px; font-family: Arial, sans-serif; }
.content {
max-width: 600px;
line-height: 1.8;
font-size: 16px;
}
.tooltip-trigger {
color: #3b82f6;
text-decoration: underline;
text-decoration-style: dotted;
cursor: help;
background: none;
border: none;
font: inherit;
padding: 0;
}
.tooltip-trigger:hover {
color: #2563eb;
}
.tooltip {
padding: 8px 12px;
background: #1e293b;
color: white;
border-radius: 6px;
font-size: 14px;
max-width: 250px;
border: none;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}
.tooltip::backdrop {
background: transparent;
}
</style>
</head>
<body>
<h2>Tooltip Pattern</h2>
<div class="content">
<p>
Web development involves three core technologies:
<button class="tooltip-trigger" popovertarget="html-tip">HTML</button> for structure,
<button class="tooltip-trigger" popovertarget="css-tip">CSS</button> for styling, and
<button class="tooltip-trigger" popovertarget="js-tip">JavaScript</button> for interactivity.
</p>
<p>
Modern frameworks like
<button class="tooltip-trigger" popovertarget="react-tip">React</button>,
<button class="tooltip-trigger" popovertarget="vue-tip">Vue</button>, and
<button class="tooltip-trigger" popovertarget="angular-tip">Angular</button>
build on these foundations.
</p>
</div>
<!-- Tooltips -->
<div id="html-tip" popover class="tooltip">
HyperText Markup Language - defines the structure of web pages
</div>
<div id="css-tip" popover class="tooltip">
Cascading Style Sheets - controls the visual presentation
</div>
<div id="js-tip" popover class="tooltip">
JavaScript - adds interactivity and dynamic behavior
</div>
<div id="react-tip" popover class="tooltip">
React - A JavaScript library for building user interfaces
</div>
<div id="vue-tip" popover class="tooltip">
Vue - Progressive JavaScript framework
</div>
<div id="angular-tip" popover class="tooltip">
Angular - Platform for building web applications
</div>
</body>
</html>
By default, popovertarget toggles the popover:
< button popovertarget = " my-popover " > Toggle </ button >
< div id = " my-popover " popover > Content </ div >
First click : Opens popover
Second click : Closes popover
Combine with popovertargetaction for specific actions:
< button popovertarget = " menu " popovertargetaction = " show " > Open </ button >
< button popovertarget = " menu " popovertargetaction = " hide " > Close </ button >
<!-- Toggle (default) -->
< button popovertarget = " menu " popovertargetaction = " toggle " > Toggle </ button >
< div id = " menu " popover > Menu content </ div >
Only <button> and <input type="button|reset|submit"> elements support popovertarget:
< button popovertarget = " popover " > Open </ button >
< input type = " button " popovertarget = " popover " value = " Open " >
< div popovertarget = " popover " > Open </ div >
< a popovertarget = " popover " > Open </ a >
Buttons with popovertarget don’t submit forms:
<!-- Won't submit form -->
< button popovertarget = " help " > Help </ button >
<!-- Will submit form -->
< button type = " submit " > Submit </ button >
<!-- Good: Clear action -->
< button popovertarget = " menu " > Open Menu </ button >
< button popovertarget = " menu " > Click </ button >
aria-label = " Open navigation menu "
< div id = " dialog " popover = " manual " >
< button popovertarget = " dialog " popovertargetaction = " hide " >
< button type = " button " popovertarget = " info " > Info </ button >
<!-- Not a form submit -->
< button type = " button " popovertarget = " help " > Help </ button >
While popovertarget works declaratively, you can also use JavaScript:
const button = document . getElementById ( ' trigger ' );
const popover = document . getElementById ( ' my-popover ' );
// Set target programmatically
button . popoverTargetElement = popover ;
console . log ( button . popoverTargetElement ); // Returns the popover element
button . setAttribute ( ' popovertarget ' , ' my-popover ' );
Buttons with popovertarget are fully keyboard accessible:
Enter/Space : Activates button and toggles popover
Tab : Moves focus to/from button
Escape : Closes auto popovers (built-in)
< div id = " menu " popover role = " menu " >
< button role = " menuitem " > Item 1 </ button >
< button role = " menuitem " > Item 2 </ button >
// Update aria-expanded dynamically
const button = document . getElementById ( ' menu-btn ' );
const popover = document . getElementById ( ' menu ' );
popover . addEventListener ( ' toggle ' , ( e ) => {
button . setAttribute ( ' aria-expanded ' , e . newState === ' open ' );
< button popovertarget = " dropdown " >
< div id = " dropdown " popover >
< button popovertarget = " info-tooltip " aria-label = " More information " >
< div id = " info-tooltip " popover class = " tooltip " >
Additional information here
< button popovertarget = " confirm " > Delete Item </ button >
< div id = " confirm " popover = " manual " >
< button popovertarget = " confirm " popovertargetaction = " hide " > Cancel </ button >
< button onclick = " deleteItem () " > Confirm </ button >
Browser Support Chrome 114+ Edge 114+ Safari 17+ Firefox 125+ (behind flag)