How to Click a Button in Selenium Python (2026)
In Selenium Python, click a button with element.click() after locating it with driver.find_element(). Always use explicit waits (WebDriverWait) before clicking to avoid ElementNotInteractableException. If .click() fails due to overlays or animations, use JavaScript click: driver.execute_script("arguments[0].click();", element).
Key Takeaways
Always wait before clicking. Clicking before an element is interactive causes ElementNotInteractableException. Use WebDriverWait with element_to_be_clickable condition before every click.
.click() fails on hidden or overlapped elements. If another element (overlay, modal, cookie banner) intercepts the click, use JavaScript click as a fallback or scroll the element into view first.
StaleElementReferenceException means the DOM changed. Find the element again after any page navigation, AJAX update, or DOM refresh before attempting to click.
CSS selectors are more reliable than XPath for buttons. button[type='submit'] or .btn-primary is less brittle than complex XPath expressions that break when layout changes.
element_to_be_clickable is not enough on SPAs. On React/Vue/Angular apps, even after the click condition is met, the event handler may not be attached yet. Add a short wait or verify the result after clicking.
Basic Button Click in Selenium Python
The simplest way to click a button:
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://example.com")
button = driver.find_element(By.CSS_SELECTOR, "button[type='submit']")
button.click()
This works when the button is already visible and interactive when the page loads. For dynamic pages (most modern web apps), you need explicit waits.
Clicking Buttons with Explicit Waits
Never click a button without waiting for it to be clickable:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("https://example.com/login")
wait = WebDriverWait(driver, 10)
# Wait until the button is clickable (visible + enabled)
submit_button = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "button[type='submit']"))
)
submit_button.click()
element_to_be_clickable waits until the element is both visible and enabled. This handles most timing issues with dynamic content.
Finding Buttons by Different Locators
By ID
button = driver.find_element(By.ID, "submit-btn")
button.click()
By CSS Selector
# By button text using CSS (limited)
button = driver.find_element(By.CSS_SELECTOR, ".btn-primary")
button.click()
# By type attribute
button = driver.find_element(By.CSS_SELECTOR, "button[type='submit']")
button.click()
# By data attribute
button = driver.find_element(By.CSS_SELECTOR, "button[data-action='save']")
button.click()
By XPath (for text content)
# Click button by visible text
button = driver.find_element(By.XPATH, "//button[text()='Save Changes']")
button.click()
# Partial text match
button = driver.find_element(By.XPATH, "//button[contains(text(), 'Save')]")
button.click()
By Link Text (for anchor elements styled as buttons)
button = driver.find_element(By.LINK_TEXT, "Get Started")
button.click()
JavaScript Click: When .click() Fails
When a button is obscured by an overlay, sticky header, or cookie banner, .click() throws ElementClickInterceptedException. Use JavaScript click:
button = driver.find_element(By.CSS_SELECTOR, "#submit-button")
driver.execute_script("arguments[0].click();", button)
When to use JavaScript click:
- Cookie consent banners blocking the element
- Sticky navigation headers overlapping content
- CSS animations still in progress
- Shadow DOM elements
- Elements with
pointer-events: nonethat need to be clicked anyway (testing purposes)
Important: JavaScript click bypasses browser event propagation. Some event handlers attached via addEventListener may not fire. Prefer .click() when possible.
Scroll Into View Before Clicking
If a button is below the fold, scroll to it first:
button = driver.find_element(By.CSS_SELECTOR, "#bottom-submit")
# Scroll the element into view
driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", button)
# Wait a moment for any sticky elements to settle
import time
time.sleep(0.5)
button.click()
Or use ActionChains to move to the element before clicking:
from selenium.webdriver.common.action_chains import ActionChains
button = driver.find_element(By.CSS_SELECTOR, "#submit-btn")
ActionChains(driver).move_to_element(button).click().perform()
Common Errors and Fixes
ElementNotInteractableException
Cause: Button exists in DOM but is not visible or not enabled.
# Wrong - clicking before element is ready
button = driver.find_element(By.ID, "submit")
button.click() # ElementNotInteractableException
# Right - wait for interactive state
button = wait.until(EC.element_to_be_clickable((By.ID, "submit")))
button.click()
ElementClickInterceptedException
Cause: Another element is covering the button.
from selenium.common.exceptions import ElementClickInterceptedException
try:
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "#submit")))
button.click()
except ElementClickInterceptedException:
# Fallback to JavaScript click
driver.execute_script("arguments[0].click();", button)
StaleElementReferenceException
Cause: The DOM refreshed between finding the element and clicking it.
from selenium.common.exceptions import StaleElementReferenceException
import time
max_retries = 3
for attempt in range(max_retries):
try:
button = wait.until(EC.element_to_be_clickable((By.ID, "submit")))
button.click()
break
except StaleElementReferenceException:
if attempt == max_retries - 1:
raise
time.sleep(0.5)
NoSuchElementException
Cause: The selector doesn't match any element.
from selenium.common.exceptions import NoSuchElementException
try:
button = driver.find_element(By.CSS_SELECTOR, "#submit-btn")
button.click()
except NoSuchElementException:
print("Button not found - check your selector")
# Use driver.page_source to inspect the DOM
Clicking Buttons in Forms
Complete form submission example:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("https://example.com/login")
wait = WebDriverWait(driver, 10)
# Fill form fields
email_field = wait.until(EC.presence_of_element_located((By.ID, "email")))
email_field.send_keys("user@example.com")
password_field = driver.find_element(By.ID, "password")
password_field.send_keys("secretpassword")
# Click submit button
submit_button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[type='submit']")))
submit_button.click()
# Verify successful login
wait.until(EC.url_contains("/dashboard"))
print("Login successful!")
Clicking Buttons in Modals and Dialogs
# Wait for modal to appear
modal = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ".modal")))
# Click button inside the modal
confirm_button = wait.until(
EC.element_to_be_clickable((By.CSS_SELECTOR, ".modal .btn-confirm"))
)
confirm_button.click()
# Wait for modal to disappear
wait.until(EC.invisibility_of_element_located((By.CSS_SELECTOR, ".modal")))
Clicking Buttons by Index (Multiple Buttons)
# Get all matching buttons
buttons = driver.find_elements(By.CSS_SELECTOR, "button.action-btn")
# Click the first one
buttons[0].click()
# Click a specific one by index
buttons[2].click()
# Filter by text and click
for button in buttons:
if button.text == "Delete":
wait.until(EC.element_to_be_clickable(button))
button.click()
break
Verifying Button Click Worked
After clicking, always verify the expected outcome:
# Verify URL changed
submit_button.click()
wait.until(EC.url_to_be("https://example.com/success"))
# Verify element appeared
submit_button.click()
success_message = wait.until(
EC.visibility_of_element_located((By.CSS_SELECTOR, ".success-toast"))
)
assert "saved" in success_message.text.lower()
# Verify element disappeared
delete_button.click()
wait.until(EC.staleness_of(item_element))
The Real Cost of Selenium Button Clicking
A reliable Selenium test that clicks a button requires:
- Proper wait strategy (explicit wait with
element_to_be_clickable) - Exception handling for
ElementClickInterceptedException,StaleElementReferenceException - JavaScript click fallback for overlay issues
- Scroll-into-view logic for off-screen buttons
- Post-click verification
That's 20-40 lines of code for a single button click. And when the page's CSS changes — new sticky header, redesigned modal — your selectors break and you maintain it again.
Alternative: AI-Powered Testing
HelpMeTest handles button clicks with natural language:
Click the "Submit" button
The AI:
- Finds the button by visual appearance and text, not brittle CSS selectors
- Waits automatically until it's interactive
- Handles overlays, scroll position, and timing without code
- Self-heals when the UI changes
A full login test in HelpMeTest:
Go to https://example.com/login
Type "user@example.com" in the email field
Type "password123" in the password field
Click the "Sign In" button
Verify the dashboard page loads
No locators. No wait strategies. No exception handling. When the UI changes, the AI adapts automatically.
When Selenium button clicking makes sense:
- Fine-grained control over event types (mousedown, mouseup separately)
- Testing JavaScript event propagation specifically
- Complex canvas or custom widget interactions
- Existing large Selenium test suite you're maintaining
When HelpMeTest makes more sense:
- User flow testing (login, checkout, signup)
- Regression testing across UI changes
- Teams without dedicated automation engineers
- Rapid test creation for new features
Summary
| Scenario | Solution |
|---|---|
| Simple click | element.click() |
| Click after page load | WebDriverWait + element_to_be_clickable |
| Click intercepted by overlay | JavaScript click |
| Element below fold | scrollIntoView + click |
| DOM refreshed | Retry with StaleElementReferenceException |
| Button not found | Check selector with driver.page_source |
The key to reliable button clicks in Selenium: always wait, always verify, always handle the exceptions.