HTML <button> reference
Jump to this section
Common attributes Jump to this section
type Jump to this section
The type attribute controls how the button behaves within a form. There's no visual difference between types, just different functionality for form submission and page behavior.
Values: button (default), submit, reset
button: A generic button with no default behavior. Use this for buttons that trigger JavaScript functions or don't interact with forms. This is the safest default to prevent accidental form submissions.submit: Submits the form data to the server. When clicked, it triggers form validation and sends the form to the URL specified in the form'sactionattribute.reset: Clears all form inputs back to their initial values.
<button type="button">normal button</button><button type="submit">submit button</button><button type="reset">reset button</button>disabled Jump to this section
Boolean attribute that makes the button non-interactive. Disabled buttons cannot be clicked, focused via keyboard, or included in form submissions. Most browsers display disabled buttons with reduced opacity and a not-allowed cursor.
Use when an action is temporarily unavailable (e.g., form validation hasn't passed, data is loading, or prerequisites aren't met). Always provide visual feedback explaining why a button is disabled.
<button disabled>disabled button</button>name / value Jump to this section
Used together with type="submit" buttons to send additional data when a form is submitted. The name acts as the key identifier, and value is the data sent to the server. This is useful when you have multiple submit buttons that perform different actions.
Use when you need to know which specific button was clicked (e.g., "Save Draft" vs "Publish" buttons in the same form).
<button type="submit" name="action" value="save">Save Draft</button>
<button type="submit" name="action" value="publish">Publish</button>
When clicked, the form data will include action=save or action=publish depending on which button was used.
autofocus Jump to this section
Automatically focuses the button when the page loads, allowing users to immediately interact with it using the keyboard. Only one element per page should have this attribute to avoid confusion.
Use on primary action buttons in dialogs or single-purpose pages (e.g., a search button on a search page). Avoid overusing this as it can disorient users and interfere with screen readers.
<button autofocus>Continue</button>
form Jump to this section
Connects a button to a form element even when the button is located outside the form in the HTML structure. The value should be the id of the form element.
Use when your page layout requires the submit button to be physically separated from the form (e.g., a modal footer or a sticky action bar).
<form id="checkout-form">
<input type="text" name="email">
</form>
<!-- Button located elsewhere in the page -->
<button type="submit" form="checkout-form">Complete Purchase</button>
formaction Jump to this section
Overrides the form's action attribute for this specific button. This allows different submit buttons in the same form to send data to different URLs.
Use when you have multiple submission paths from a single form (e.g., "Save" vs "Save and Continue").
<form action="/save">
<input type="text" name="title">
<button type="submit">Save</button>
<button type="submit" formaction="/save-and-publish">Save & Publish</button>
</form>
formmethod Jump to this section
Overrides the form's HTTP method (GET or POST) for this specific button. Rarely needed, but useful when one button should use a different HTTP verb.
<button type="submit" formmethod="POST">Submit</button>
<button type="submit" formmethod="GET">Preview</button>
formenctype Jump to this section
Overrides how form data is encoded when submitted. The value must be one of: application/x-www-form-urlencoded (default), multipart/form-data (required for file uploads), or text/plain.
<button type="submit" formenctype="multipart/form-data">Upload Files</button>
formnovalidate Jump to this section
Boolean attribute that bypasses HTML5 form validation for this specific button. Useful for "Save Draft" buttons where you want to allow incomplete data.
Use when you need to submit a form that hasn't passed validation (e.g., saving progress without requiring all fields to be completed).
<form>
<input type="email" required>
<button type="submit">Submit</button>
<button type="submit" formnovalidate>Save Draft</button>
</form>
formtarget Jump to this section
Specifies where to display the response after form submission. Values: _self (same window), _blank (new tab), _parent, _top, or a named frame/iframe.
<button type="submit" formtarget="_blank">Submit in New Tab</button>
aria-label Jump to this section
Provides an accessible label for the button that overrides its visible text content. Essential for icon-only buttons that lack text.
Use for buttons that only contain icons, images, or symbols without descriptive text. Screen readers will announce this label instead of the button's contents.
<button aria-label="Close dialog">×</button>
<button aria-label="Search"><svg>...</svg></button>
aria-pressed Jump to this section
Indicates whether a toggle button is currently pressed (on) or not pressed (off). This communicates the button's state to assistive technologies.
Use for buttons that switch between two states (e.g., "Mute/Unmute," "Bold text on/off," "Follow/Following").
<button aria-pressed="false" onclick="this.setAttribute('aria-pressed',
this.getAttribute('aria-pressed') === 'false' ? 'true' : 'false')">
Mute
</button>
aria-expanded Jump to this section
Indicates whether a button controls content that is currently expanded (true) or collapsed (false). Used for buttons that show/hide content like dropdowns, accordions, or menus.
<button aria-expanded="false" aria-controls="menu-dropdown">Menu</button>
<div id="menu-dropdown" hidden>...</div>
aria-controls Jump to this section
Identifies the element(s) that are controlled by the button using their id values. This creates a programmatic relationship between the button and the content it affects.
Pair with aria-expanded to explicitly link a button to the content it controls.
<button aria-controls="details-panel">Show Details</button>
<div id="details-panel">...</div>
aria-describedby Jump to this section
References additional descriptive text by its id. This provides extra context about the button's purpose or consequences of clicking it.
Use when a button needs additional explanation that isn't part of its label (e.g., warning text, help text).
<button aria-describedby="delete-warning">Delete Account</button>
<span id="delete-warning">This action cannot be undone.</span>
title Jump to this section
Provides a tooltip that appears on hover. While commonly used, it's not accessible to keyboard-only users or touch devices, so don't rely on it for critical information.
Use for supplementary information only. Never use as a replacement for proper accessible labels.
<button title="Saves your changes without publishing">Save Draft</button>
tabindex Jump to this section
Controls whether and in what order an element receives keyboard focus. Buttons are focusable by default (tabindex="0"), so you rarely need to set this.
Values:
0: Normal tab order (default for buttons)-1: Removed from tab order but can be focused programmatically- Positive numbers: Custom tab order
<button tabindex="-1">Not keyboard accessible</button>
accesskey Jump to this section
Defines a keyboard shortcut to activate the button. The actual key combination varies by browser and OS (e.g., Alt+key on Windows, Control+Option+key on Mac).
Use sparingly as access keys can conflict with browser or screen reader shortcuts.
<button accesskey="s">Save (Alt+S)</button>
data-* attributes Jump to this section
Custom attributes for storing extra information on the button element. Commonly used to pass data to JavaScript handlers or for CSS styling hooks.
Use to store any custom data your JavaScript needs without using non-standard attributes.
<button data-user-id="12345" data-action="delete">Delete User</button>
<script>
button.addEventListener('click', (e) => {
const userId = e.target.dataset.userId; // "12345"
const action = e.target.dataset.action; // "delete"
});
</script>
id Jump to this section
Provides a unique identifier for the button on the page. Used for CSS targeting, JavaScript selection, linking with labels, and fragment navigation.
<button id="submit-btn">Submit</button>
<script>
document.getElementById('submit-btn').addEventListener('click', ...);
</script>
class Jump to this section
Assigns one or more CSS class names for styling or JavaScript selection. Multiple classes are separated by spaces.
<button class="btn btn-primary btn-lg">Large Primary Button</button>
style Jump to this section
Applies inline CSS styles directly to the button. Generally avoid in favor of external stylesheets or classes for better maintainability.
<button style="background-color: #007bff; color: white;">Styled Button</button>
popovertarget Jump to this section
Connects a button to a popover element using the Popover API. When clicked, the button will show the specified popover.
Use for modern, accessible tooltips, dropdowns, and dialogs without JavaScript.
<button popovertarget="my-popover">Open Popover</button>
<div id="my-popover" popover>Popover content</div>
popovertargetaction Jump to this section
Specifies what action the button performs on the popover: show, hide, or toggle (default).
<button popovertarget="my-popover" popovertargetaction="show">Open</button>
<button popovertarget="my-popover" popovertargetaction="hide">Close</button>
Styling basics Jump to this section
Buttons are typically inline-level elements styled with padding, border, background, and cursor. Keep hit targets large enough (44×44px recommended for touch).
Examples Jump to this section
Primary button Jump to this section
.btn-primary {
background: mediumseagreen;
color: white;
border: none;
padding: 10px 16px;
border-radius: 6px;
cursor: pointer;
}
Outline button Jump to this section
.btn-outline {
background: transparent;
border: 2px solid mediumseagreen;
color: mediumseagreen;
padding: 10px 16px;
border-radius: 6px;
cursor: pointer;
}
Ghost button Jump to this section
.btn-ghost {
background: transparent;
border: none;
color: #333;
padding: 10px 16px;
text-decoration: underline;
cursor: pointer;
}
Pill button Jump to this section
.btn-pill {
background: slateblue;
color: white;
border: none;
padding: 10px 24px;
border-radius: 50px;
cursor: pointer;
}
Disabled state Jump to this section
.btn-primary:disabled {
background: #e0e0e0;
color: #999;
cursor: not-allowed;
opacity: 0.6;
}
Size variants Jump to this section
.btn-small {
padding: 6px 12px;
font-size: 13px;
border-radius: 4px;
}
.btn-medium {
padding: 10px 16px;
font-size: 15px;
border-radius: 6px;
}
.btn-large {
padding: 14px 24px;
font-size: 17px;
border-radius: 8px;
}
Icon button Jump to this section
/* Set the button text to '+' */
.btn-icon {
background: royalblue;
color: white;
border: none;
width: 44px;
height: 44px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
Gradient button Jump to this section
.btn-gradient {
background: linear-gradient(135deg, #abb8f5 0%, #562687 100%);
color: white;
border: none;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
}
Shadow button Jump to this section
.btn-shadow {
background: white;
color: #333;
border: 1px solid #ddd;
padding: 10px 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.5); /* horizontal offset,vertical offset,blur radius,color */
cursor: pointer;
}
Hover states Jump to this section
Add hover effects to provide visual feedback. Always include cursor: pointer and use transition for smooth animations.
Color change on hover Jump to this section
.btn-primary {
background: mediumseagreen;
color: white;
transition: background 0.2s ease;
cursor: pointer;
}
.btn-primary:hover {
background: seagreen;
}
Lift effect on hover Jump to this section
.btn-lift {
background: royalblue;
color: white;
transition: all 0.2s ease;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.btn-lift:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
Active/pressed states Jump to this section
Style the :active state to provide feedback when clicked.
.btn-primary {
background: mediumseagreen;
color: white;
transition: transform 0.1s ease;
cursor: pointer;
}
.btn-primary:active {
transform: scale(0.95);
}
JavaScript patterns Jump to this section
Buttons are common interaction targets in web applications. Always use addEventListener instead of inline event handlers for better maintainability and security. Respect the type attribute so submit buttons trigger form submission while regular buttons handle custom logic.
Basic click handler Jump to this section
The most common pattern: responding to a button click. Use addEventListener('click', ...) to attach behavior to your button.
const button = document.getElementById('js-alert');
button.addEventListener('click', () => {
alert('Button clicked!');
});
Accessing event details Jump to this section
Access information about the click event, such as which button was clicked or modifier keys held.
const button = document.getElementById('js-event');
button.addEventListener('click', (event) => {
alert('Clicked element:', event.target);
alert('Ctrl key held:', event.ctrlKey);
alert('Mouse position:', event.clientX, event.clientY);
});
Disable while processing Jump to this section
Prevent multiple clicks during async operations like API calls. Disable the button, update the text to show progress, then re-enable when complete.
const saveBtn = document.getElementById('js-process');
saveBtn.addEventListener('click', async () => {
// Disable button and show loading state
saveBtn.disabled = true;
const originalText = saveBtn.textContent;
saveBtn.textContent = 'Saving…';
try {
await saveData(); // Your async operation
saveBtn.textContent = 'Saved!';
setTimeout(() => {
saveBtn.textContent = originalText;
}, 2000);
} catch (error) {
saveBtn.textContent = 'Error';
console.error(error);
} finally {
saveBtn.disabled = false;
}
});
Toggle button (ARIA) Jump to this section
Create accessible toggle buttons that announce their state to screen readers using aria-pressed. Useful for features like mute/unmute, bold text, or favorites.
const toggleBtn = document.getElementById('js-toggle');
toggleBtn.addEventListener('click', () => {
const isPressed = toggleBtn.getAttribute('aria-pressed') === 'true';
// Toggle the pressed state
toggleBtn.setAttribute('aria-pressed', !isPressed);
// Update button text or icon
toggleBtn.textContent = isPressed ? 'Mute' : 'Unmuted';
});
Show/hide content (collapsible) Jump to this section
Control visibility of content sections using aria-expanded for accessibility. Common for dropdowns, accordions, and "show more" buttons.
const expandBtn = document.getElementById('js-expand');
const panel = document.getElementById('details-panel');
expandBtn.addEventListener('click', () => {
const isExpanded = expandBtn.getAttribute('aria-expanded') === 'true';
// Toggle visibility
expandBtn.setAttribute('aria-expanded', !isExpanded);
panel.style.display = isExpanded ? 'none' : 'block';
// Update button text
expandBtn.textContent = isExpanded ? 'Show details' : 'Hide details';
});
Multiple buttons with data attributes Jump to this section
Use data-* attributes to handle similar buttons with different actions. Avoids creating separate handlers for each button.
document.querySelectorAll('.action-btn').forEach(button => {
button.addEventListener('click', (e) => {
const action = e.target.dataset.action;
switch(action) {
case 'save':
alert('Saving...');
break;
case 'delete':
if (confirm('Are you sure?')) {
alert('Deleting...');
}
break;
case 'share':
alert('Opening share dialog...');
break;
}
});
});
Keyboard shortcuts (accesskey alternative) Jump to this section
Implement custom keyboard shortcuts that work reliably across all platforms. Better than accesskey which conflicts with browser shortcuts.
const saveBtn = document.getElementById('js-shortcut');
// Click handler
saveBtn.addEventListener('click', () => {
alert('Saving document...');
});
// Keyboard shortcut
document.addEventListener('keydown', (e) => {
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
e.preventDefault(); // Prevent browser's default save
saveBtn.click(); // Trigger button click
}
});
Prevent default form submission Jump to this section
Control form submission manually with JavaScript validation or AJAX. Use event.preventDefault() to stop the default form submit behavior.
const form = document.getElementById('custom-form');
form.addEventListener('submit', async (event) => {
event.preventDefault(); // Stop default form submission
const formData = new FormData(form);
const email = formData.get('email');
try {
const response = await fetch('/api/submit', {
method: 'POST',
body: formData
});
if (response.ok) {
alert('Form submitted successfully!');
}
} catch (error) {
alert('Submission failed');
console.error(error);
}
});
Debouncing rapid clicks Jump to this section
Prevent users from triggering an action multiple times by rapidly clicking. Useful for expensive operations or API calls.
const debounceBtn = document.getElementById('js-debounce');
let timeout;
let clickCount = 0;
debounceBtn.addEventListener('click', () => {
clickCount++;
clearTimeout(timeout);
timeout = setTimeout(() => {
alert(`Action executed after ${clickCount} clicks`);
clickCount = 0;
}, 500);
});
Dynamic button creation Jump to this section
Programmatically create buttons and attach event listeners. Useful when building UI from data or API responses.
const container = document.getElementById('button-container');
const items = ['Home', 'About', 'Contact'];
items.forEach(item => {
const button = document.createElement('button');
button.textContent = item;
button.className = 'btn-sample';
button.style.cssText = 'background:mediumseagreen;color:white;border:none;padding:8px 14px;border-radius:6px;cursor:pointer;margin-right:8px;';
button.addEventListener('click', () => {
alert(`Navigating to ${item}`);
});
container.appendChild(button);
});
Loading state with spinner Jump to this section
Replace button text with a loading indicator during async operations. Provides better visual feedback than just disabling the button.
const loadBtn = document.getElementById('js-spinner');
loadBtn.addEventListener('click', async () => {
const originalHTML = loadBtn.innerHTML;
// Show spinner (using Unicode spinner character)
loadBtn.innerHTML = '⏳ Loading...';
loadBtn.disabled = true;
try {
await fetchData(); // Your async operation
loadBtn.innerHTML = '✓ Done!';
} catch (error) {
loadBtn.innerHTML = '✗ Failed';
} finally {
setTimeout(() => {
loadBtn.innerHTML = originalHTML;
loadBtn.disabled = false;
}, 2000);
}
});
// Add CSS for spinner animation
const style = document.createElement('style');
style.textContent = '@keyframes spin { to { transform: rotate(360deg); } }';
document.head.appendChild(style);
Confirm before destructive actions Jump to this section
Always ask for confirmation before performing destructive actions like deletion. Prevents accidental data loss.
const deleteBtn = document.getElementById('js-confirm');
deleteBtn.addEventListener('click', async () => {
const confirmed = confirm('Are you sure you want to delete your account? This cannot be undone.');
if (!confirmed) {
return; // User cancelled
}
deleteBtn.disabled = true;
deleteBtn.textContent = 'Deleting...';
try {
await deleteAccount();
alert('Account deleted successfully');
deleteBtn.textContent = 'Delete account';
} catch (error) {
alert('Failed to delete account');
deleteBtn.disabled = false;
deleteBtn.textContent = 'Delete account';
}
});
