Disabling the WordPress login shake animation is a small interface customization that removes the horizontal shaking effect shown by the native WordPress login form after certain authentication or password-recovery errors.
By default, WordPress can shake the login form when errors such as an incorrect password, invalid username or empty credential field are returned.
The effect looks roughly like this:
user submits invalid credentials
↓
WordPress detects a matching error
↓
login form receives the "shake" class
↓
CSS animation moves the form horizontally
The animation is purely presentational.
Removing it does not:
- disable login errors;
- change authentication;
- make invalid credentials valid;
- remove login security;
- change password validation;
- prevent failed-login logging;
- disable rate limiting;
- change the text of WordPress error messages.
It simply stops WordPress from animating the form when selected errors occur.
This guide explains how the WordPress login shake works, which errors trigger it, how to disable it cleanly with the shake_error_codes filter, alternative methods you may encounter, accessibility considerations and what the change does and does not affect.
What is the WordPress login shake animation?
Open the standard WordPress login page:
https://example.com/wp-login.php
and submit certain invalid credentials.
WordPress may animate the login form from side to side while displaying the relevant error.
The animation is intended to reinforce visually that something went wrong.
Conceptually:
invalid login
↓
error message
+
shake animation
The important distinction is that these are two separate pieces of feedback.
The error message explains the problem.
The shake animation visually emphasizes it.
The shake is generated by WordPress Core
This is not normally an animation created by your theme.
WordPress Core contains the wp_shake_js() function specifically for this behavior.
The official wp_shake_js() documentation describes the function as outputting the JavaScript responsible for shaking the form on the login page.
Its current implementation is extremely small.
Conceptually, WordPress outputs JavaScript equivalent to:
document
.querySelector('form')
.classList
.add('shake');
The browser then applies the corresponding WordPress login-page CSS animation to the form.
WordPress does not shake the form after every possible error
The behavior is conditional.
Inside the current WordPress login-page lifecycle, Core defines a list of error codes that are allowed to trigger the shake.
The official login_header() source currently includes error codes such as:
empty_password
empty_email
invalid_email
invalidcombo
empty_username
invalid_username
incorrect_password
retrieve_password_email_failure
If the current error matches one of the configured codes, WordPress schedules the shake script.
How WordPress decides whether to shake the login form
The process can be simplified as:
login page receives WP_Error
↓
WordPress reads the error code
↓
compares it with shake_error_codes
↓
matching code?
│
├── No
│ └── no shake script
│
└── Yes
└── attach wp_shake_js()
to login_footer
at priority 12
This architecture gives us a particularly clean place to disable the effect.
The cleanest method: filter shake_error_codes
WordPress applies the:
shake_error_codes
filter to the array before deciding whether the animation should run.
Therefore, if you return an empty array, there are no error codes capable of triggering the shake.
Add:
add_filter( 'shake_error_codes', '__return_empty_array' );
That is the complete functional change.
What this code does
Normally WordPress effectively has:
$shake_error_codes = array(
'empty_password',
'empty_email',
'invalid_email',
'invalidcombo',
'empty_username',
'invalid_username',
'incorrect_password',
'retrieve_password_email_failure',
);
Then Core runs that array through:
apply_filters(
'shake_error_codes',
$shake_error_codes
);
Your filter changes the result to:
array()
WordPress then has nothing to match against.
The result becomes:
login error occurs
↓
error message remains
↓
no error is eligible for shake
↓
wp_shake_js() is not attached
↓
form remains still
Why this method is better than overriding the animation with CSS
You could theoretically add CSS such as:
.login form.shake {
animation: none !important;
}
That may visually suppress the effect.
But WordPress would still:
- identify the error as shake-worthy;
- attach
wp_shake_js(); - output its inline JavaScript;
- add the
shakeclass; - have your CSS neutralize the final result.
Filtering the error list prevents the behavior earlier in the process.
Instead of:
trigger feature
↓
undo feature
you get:
do not trigger feature
That is generally the cleaner implementation.
Where should you add the code?
There are several reasonable locations.
You can place the filter in:
- a small custom plugin;
- a site-specific functionality plugin;
- an appropriate child theme;
- a code-management system that safely executes PHP snippets.
For permanent site functionality, a plugin-based implementation is usually preferable to modifying a parent theme.
Do not edit wp-login.php
The function responsible for the effect lives in WordPress Core.
That does not mean you should edit:
wp-login.php
directly.
Core modifications are fragile because WordPress updates can replace those files.
The filter exists specifically so the behavior can be changed without modifying Core.
A complete minimal plugin
If you want the change to remain independent of your theme, create a small plugin.
For example:
<?php
/**
* Plugin Name: Disable Login Shake
* Description: Disables the native WordPress login shake animation.
*/
defined( 'ABSPATH' ) || exit;
add_filter(
'shake_error_codes',
'__return_empty_array'
);
Save it as something like:
disable-login-shake.php
inside:
/wp-content/plugins/disable-login-shake/
and activate it through the Plugins screen.
Why use __return_empty_array()?
WordPress provides several convenience functions for filters that need to return simple values.
__return_empty_array() does exactly what its name suggests:
return array();
The official __return_empty_array() documentation describes it as a helper function that returns an empty array.
That makes this:
add_filter(
'shake_error_codes',
'__return_empty_array'
);
more concise than creating an unnecessary callback:
add_filter(
'shake_error_codes',
function ( $codes ) {
return array();
}
);
Both approaches express the same idea.
You can also disable the shake only for selected errors
The filter does not have to remove every error code.
Because it receives the complete array, you can selectively modify it.
For example, imagine you want to stop the animation for an incorrect password but preserve it for the other default cases.
add_filter(
'shake_error_codes',
function ( $codes ) {
return array_values(
array_diff(
$codes,
array( 'incorrect_password' )
)
);
}
);
Now:
incorrect password
→ no shake
other configured errors
→ default WordPress behavior
You can also add custom error codes
The same filter works in the opposite direction.
A plugin that introduces a custom login error could add its error code to the list:
add_filter(
'shake_error_codes',
function ( $codes ) {
$codes[] = 'my_custom_login_error';
return $codes;
}
);
This helps explain why filtering the array is architecturally cleaner than targeting the final CSS animation.
You are modifying the actual decision WordPress makes.
Alternative method: remove wp_shake_js()
You may encounter another technique in WordPress tutorials:
remove_action(
'login_footer',
'wp_shake_js',
12
);
The idea is valid, but timing matters.
WordPress conditionally attaches wp_shake_js() while generating the login header after examining the current error.
Removing an action before WordPress has added it achieves nothing.
A timing-aware removal
The official wp_shake_js() reference includes an example that hooks an earlier callback into login_footer and removes the shake callback before priority 12 executes.
Conceptually:
add_action(
'login_footer',
function () {
remove_action(
'login_footer',
'wp_shake_js',
12
);
},
1
);
The order becomes:
login_footer priority 1
↓
remove wp_shake_js
login_footer priority 12
↓
nothing left to execute
But filtering shake_error_codes is simpler
If your intention is simply:
never shake the native login form
then:
add_filter(
'shake_error_codes',
'__return_empty_array'
);
expresses that intention more directly.
You are telling WordPress:
No login error should trigger shaking.
rather than waiting for the callback to be registered and then removing it.
Be careful with outdated login_head snippets
You may find old examples that attempt something like:
add_action(
'login_head',
function () {
remove_action(
'login_head',
'wp_shake_js',
12
);
}
);
That should not be copied blindly into current WordPress code.
Current Core conditionally attaches wp_shake_js() to:
login_footer
not login_head.
WordPress changes over time. A snippet being repeated on fifty websites does not magically make its assumptions current.
login_head and login_footer are different lifecycle points
The WordPress login screen has its own collection of hooks.
For a broader explanation, see WordPress Login Hooks Explained.
The official login_head documentation describes a hook that runs in the login page’s <head>.
By contrast, the shake script is currently scheduled for the footer.
That distinction matters when removing callbacks.
login_enqueue_scripts is useful for login-page assets
If your broader objective is to customize the WordPress login screen with your own CSS or JavaScript, WordPress provides:
login_enqueue_scripts
The official login_enqueue_scripts documentation identifies it as the appropriate hook for enqueueing scripts and styles on login and registration-related screens.
For example:
add_action(
'login_enqueue_scripts',
function () {
wp_enqueue_style(
'my-login',
plugin_dir_url( __FILE__ ) . 'login.css',
array(),
'1.0.0'
);
}
);
That is useful for visual customization.
But you do not need a stylesheet merely to disable the native shake when the dedicated PHP filter can prevent it.
Does removing the shake remove the error message?
No.
This distinction is important.
The default behavior is:
authentication error
↓
WordPress creates WP_Error
↓
error message displayed
+
optional shake triggered
Removing the shake changes only the second branch:
authentication error
↓
WordPress creates WP_Error
↓
error message displayed
+
no shake
The user still receives feedback explaining that login failed.
Does disabling the shake change authentication?
No.
The shake happens at the presentation layer.
Authentication happens deeper in WordPress.
For example, WordPress uses authentication functions and filters to validate usernames, email addresses and passwords before the visual response is generated.
The official WordPress authentication flow returns WP_User on success and WP_Error when authentication fails.
The login screen then decides how that error should be presented.
The architecture is roughly:
credentials
↓
authentication
↓
success or WP_Error
↓
login-page presentation
↓
error message
+
optional shake
Interface behavior and authentication security are separate
This is the same distinction discussed throughout WordPress Login Hooks Explained.
A visual customization does not alter the underlying authentication rule.
Removing:
shake animation
does not remove:
password verification
and adding a more dramatic animation would not make authentication more secure either.
Does disabling the shake improve WordPress security?
Not meaningfully.
This is an interface preference, not a security control.
It does not:
- limit login attempts;
- block brute-force attacks;
- hide usernames;
- enable two-factor authentication;
- change the login URL;
- block malicious IP addresses;
- strengthen passwords.
If your objective is authentication security, start with A WordPress Login Hardening Checklist.
Use actual controls against repeated login attempts
Automated attackers do not become discouraged because the login box stopped dancing.
For repeated authentication attempts, controls such as rate limiting and temporary lockouts are far more relevant.
See How to Limit Login Attempts in WordPress for that separate problem.
Monitor failed authentication separately
Likewise, disabling a visual animation does not affect whether failed login activity can be recorded.
For operational visibility, see How to Monitor WordPress Login Attempts.
The responsibilities remain separate:
shake animation
→ presentation
error message
→ user feedback
authentication
→ credential validation
rate limiting
→ abuse control
logging
→ visibility
Does the shake expose whether a password is wrong?
The animation itself is not a meaningful security boundary.
The information available to a user depends primarily on the error handling and authentication response, not on whether the form moves.
If you are reviewing what WordPress reveals through login errors, see WordPress Login Error Messages Explained.
Why disable the login shake?
There are several reasonable motivations.
1. Cleaner visual design
A heavily customized or branded login page may use a quieter interaction language.
A side-to-side shake can feel inconsistent with the rest of the interface.
If you are redesigning the complete screen, see How to Customize the WordPress Login Page.
2. Client-facing WordPress installations
Agency and managed WordPress installations often customize the login experience to feel less like a generic WordPress utility screen.
For that workflow, see Branding the WordPress Login Screen for Clients.
3. Motion sensitivity
Some users prefer interfaces with reduced motion.
A shaking login form is non-essential motion triggered directly by interaction.
The error can be communicated perfectly well without moving the entire form horizontally.
4. Simpler feedback hierarchy
A clear error message may be enough.
Instead of:
red error notice
+
horizontal animation
+
focus change
+
possibly other custom effects
a site may deliberately choose:
clear error notice
+
stable form
The shake animation is non-essential feedback
When a password is incorrect, the important information is:
The credentials were not accepted.
The physical movement of the form is not necessary to understand that result.
This makes the shake a good example of animation that can be removed without removing functionality.
Motion accessibility is a valid reason to remove it
WCAG includes guidance around motion animation triggered by user interaction.
The W3C’s Animation from Interactions guidance addresses the ability to disable non-essential motion triggered by interaction.
A failed login is exactly that kind of interaction:
submit credentials
↓
error
↓
motion
Removing the motion while preserving the error is a straightforward reduced-motion improvement.
What about prefers-reduced-motion?
Another approach would be to keep the animation for users with no expressed motion preference and suppress it when:
prefers-reduced-motion: reduce
matches.
MDN documents prefers-reduced-motion as a media feature for detecting whether the user has requested reduced non-essential motion.
For a general site-wide motion strategy, this is excellent practice.
For this particular WordPress effect, however, many site owners simply choose to disable the shake entirely because it contributes little essential information.
You can preserve the shake only for users without a reduced-motion preference
If you specifically want conditional behavior, you could leave the WordPress mechanism intact and neutralize the animation for reduced-motion users with CSS loaded on the login page.
Conceptually:
@media (prefers-reduced-motion: reduce) {
.login form.shake {
animation: none !important;
}
}
This approach has a different objective from the PHP filter.
The PHP filter says:
disable the WordPress login shake globally
The CSS approach says:
preserve it normally
but suppress the visible animation
for reduced-motion users
Choose the method according to the requirement
If your requirement is:
I never want this animation.
use:
add_filter(
'shake_error_codes',
'__return_empty_array'
);
If your requirement is:
I want the animation normally,
but not when reduced motion is requested.
use an appropriate reduced-motion CSS override on the login screen.
Do not remove visual feedback completely
A login form that does nothing visible after invalid credentials is worse than a form that shakes too much.
After removing the animation, confirm that the error remains:
- visible;
- readable;
- close to the form;
- understandable without color alone.
Error messages matter more than animation
An error such as:
Authentication failed.
may technically report failure but provide little guidance.
A useful login experience should balance:
clarity
+
security
+
recoverability
For a deeper look at WordPress’s authentication feedback, continue with WordPress Login Error Messages Explained.
Do not confuse login-page customization with login hardening
WordPress login projects often combine several changes:
- custom logo;
- custom colors;
- custom login URL;
- different error messages;
- removed shake animation;
- rate limiting;
- two-factor authentication.
These controls do not all solve the same problem.
A useful classification is:
VISUAL
logo
colors
typography
shake animation
NAVIGATION
custom login URL
post-login redirect
FEEDBACK
error messages
notices
SECURITY
strong authentication
rate limiting
2FA
monitoring
Keeping these responsibilities separate makes WordPress login customization easier to maintain.
Changing the login URL is another separate control
Some installations replace the standard /wp-login.php entry point with a custom address.
If you are considering that approach, see How to Change the WordPress Login URL and Does Hiding wp-login.php Actually Help Security?.
Again:
custom URL
≠
shake removal
≠
authentication security
Will the filter work on a custom frontend login form?
Not necessarily.
The native shake behavior discussed here belongs to the WordPress login-page rendering lifecycle.
A plugin or theme may create a completely independent frontend form with its own:
- HTML;
- CSS;
- JavaScript;
- validation;
- animations.
If that custom form shakes after an error, the animation may have nothing to do with wp_shake_js().
Inspect the actual form implementation
If:
add_filter(
'shake_error_codes',
'__return_empty_array'
);
does not affect your login form, determine whether the page is actually using the native WordPress login interface.
A custom membership plugin, e-commerce plugin or theme may implement its own login experience.
What about WooCommerce login forms?
WooCommerce can expose customer authentication through frontend account flows rather than the native wp-login.php interface.
Those forms have their own frontend markup and behavior.
Removing WordPress’s native login shake therefore should not be assumed to disable animations created independently by WooCommerce, a theme or another extension.
For the broader customer account architecture, see WooCommerce Account and Checkout Pages, Explained.
What about a custom WordPress login page?
If you have customized the native login screen rather than replacing it, the filter can still be relevant because the underlying WordPress login lifecycle remains in use.
If the implementation completely replaces the native form, inspect the custom animation logic separately.
This distinction is important when using TheOneWP Custom Login Page or any other login customization system.
How to test that the shake is disabled
Use a private browser window or a logged-out browser session.
Open:
https://example.com/wp-login.php
or the site’s configured login URL.
Then deliberately test several invalid states.
Test 1: empty username
Submit the form without a username.
Expected:
error message
+
no shake
Test 2: empty password
Enter a username but leave the password empty.
Expected:
error message
+
no shake
Test 3: invalid username
Use a known non-existent test username.
Expected:
authentication fails
+
error remains
+
no shake
Test 4: incorrect password
Use a test account with an intentionally incorrect password.
Expected:
authentication fails
+
error remains
+
no shake
Test 5: successful login
Finally, log in using valid credentials.
Confirm that authentication and the normal post-login flow still work.
Do not test security changes using an account you cannot recover
The shake filter itself is low risk, but login customization projects often include several changes at once.
If you are also changing:
- the login URL;
- authentication filters;
- redirects;
- user restrictions;
- two-factor authentication;
keep an authenticated administrator session open while testing in a separate browser session.
For larger changes, use a staging environment first. See WordPress Staging Site Best Practices.
If the form still shakes, check for custom CSS or JavaScript
After applying the filter, WordPress Core should no longer consider native errors eligible for its own shake behavior.
If movement remains, inspect whether another component is responsible.
Possible sources include:
- a login customization plugin;
- a security plugin;
- a membership plugin;
- custom theme code;
- custom JavaScript;
- a page builder;
- cached login-page assets.
Use browser DevTools to inspect the form
After triggering an error, inspect the login form.
Check:
- whether the
shakeclass appears; - which CSS animation is active;
- which stylesheet defines it;
- whether custom JavaScript adds another class;
- whether the movement comes from WordPress Core or another component.
This is faster than adding increasingly aggressive CSS until something stops moving.
Check caching if your changes appear to do nothing
PHP filters are evaluated server-side, but a customized login system may also involve cached assets or optimization layers.
If you are testing CSS-based reduced-motion behavior, clear relevant:
- browser cache;
- page cache;
- CDN cache;
- generated CSS;
- asset optimization cache.
Do you need to disable the login shake?
No.
Leaving it enabled is not inherently wrong.
The question is whether the animation fits the experience you want.
Keep it if:
- you prefer the default WordPress interaction;
- it fits your login-page design;
- you have no reason to change it.
Consider removing it if:
- you want a calmer login interface;
- you are building a polished client-facing login experience;
- you are reducing unnecessary interface motion;
- the animation conflicts with your visual design;
- the error message already provides sufficient feedback.
TheOneWP can disable the login shake without custom code
If you are using TheOneWP, the same type of login cleanup can be handled through its modular login customization tools rather than maintaining one-off snippets across multiple WordPress installations.
The broader login stack can also be combined with Custom Login Page when the native login screen needs complete visual customization.
The important principle remains the same: visual cleanup should stay separate from authentication security.
Removing the shake is an interface decision.
Controls such as Two-Factor Authentication address authentication security instead.
WordPress login shake checklist
- Confirm that you are using the native WordPress login screen.
- Understand that the shake is presentation, not authentication logic.
- Keep login error messages visible.
- Use the
shake_error_codesfilter for a clean global removal. - Return an empty array when no errors should trigger shaking.
- Prefer
__return_empty_arrayfor the simplest implementation. - Do not edit
wp-login.php. - Do not rely blindly on old
login_headremoval snippets. - Remember that current Core attaches
wp_shake_js()tologin_footer. - Use the correct priority when manually removing the callback.
- Use
login_enqueue_scriptsfor login-specific custom styles and scripts. - Consider
prefers-reduced-motionif you want conditional rather than global removal. - Do not remove error feedback together with animation.
- Do not treat shake removal as a security feature.
- Use rate limiting for repeated login attempts.
- Use monitoring for authentication visibility.
- Use two-factor authentication when stronger account protection is required.
- Test empty credentials.
- Test invalid credentials.
- Test successful authentication.
- Test password-recovery flows where relevant.
- Test custom login URLs separately.
- Test custom frontend login forms separately.
- Inspect plugin-generated animation if movement remains.
- Use a staging environment for broader login customizations.
Related guides
- WordPress Login Hooks Explained
- WordPress Login Error Messages Explained
- How to Customize the WordPress Login Page
- Branding the WordPress Login Screen for Clients
- A WordPress Login Hardening Checklist
- How to Limit Login Attempts in WordPress
Final recommendation
If you want to disable the native WordPress login shake completely, use the dedicated filter:
add_filter(
'shake_error_codes',
'__return_empty_array'
);
It is concise, uses WordPress’s existing extension mechanism and prevents the shake from being scheduled rather than trying to visually override it afterwards.
The underlying process becomes:
login attempt
↓
authentication fails
↓
WordPress creates error
↓
error message displayed
↓
shake_error_codes is empty
↓
no shake script
↓
stable login form
Keep the distinction between feedback and decoration clear.
The user still needs to know that authentication failed and what they can do next.
They do not need the entire form to move sideways to discover that fact.
And if your objective is stronger login security, work on the actual authentication layers instead: strong credentials, rate limiting, two-factor authentication, sensible error handling and monitoring.
The login shake is a visual effect.
Treat it like one.

