Shake Effect

Quick attention/error shake animation. Perfect for form validation feedback and drawing attention to important elements.

Domma.effects.shake()

The shake() effect applies a quick shake animation to draw attention or signal an error. Supports horizontal, vertical, and both directions with configurable intensity and iterations.

// Shake an invalid input
Domma.effects.shake('#email-input');

// Vertical shake with callback
Domma.effects.shake('.alert', {
  direction: 'vertical',
  intensity: 4,
  iterations: 2,
  onComplete: () => console.log('Shake done')
});

// Intense shake
Domma.effects.shake('.error-box', {
  intensity: 12,
  duration: 800,
  direction: 'both'
});

Demo: Shake Directions

Three shake directions: horizontal, vertical, and both axes simultaneously.

Demo: Shake Directions
Horizontal
Vertical
Both
<div class="shake-target bg-primary text-white" id="shake-h">Horizontal</div>
<div class="shake-target bg-success text-white" id="shake-v">Vertical</div>
<div class="shake-target bg-danger text-white" id="shake-both">Both</div>
<button type="button" class="btn btn-primary" id="shake-start-h">Shake Horizontal</button>
<button type="button" class="btn btn-success" id="shake-start-v">Shake Vertical</button>
<button type="button" class="btn btn-danger" id="shake-start-both">Shake Both</button>
/**
 * Demo: Shake Directions - from public/showcase/effects/shake.
 */
export function mount(root) {
        // Demo 1: Directions
    $(root).find('#shake-start-h').on('click', () => {
          Domma.effects.shake('#shake-h', {
            direction: 'horizontal',
            respectMotionPreference: false
          });
        });
    $(root).find('#shake-start-v').on('click', () => {
          Domma.effects.shake('#shake-v', {
            direction: 'vertical',
            respectMotionPreference: false
          });
        });
    $(root).find('#shake-start-both').on('click', () => {
          Domma.effects.shake('#shake-both', {
            direction: 'both',
            respectMotionPreference: false
          });
        });
}
Domma.effects.shake('#el', { direction: 'horizontal' }); // Default
Domma.effects.shake('#el', { direction: 'vertical' });
Domma.effects.shake('#el', { direction: 'both' });

Demo: Intensity Levels

Different shake intensities from subtle to extreme.

Demo: Intensity Levels
Subtle (2px)
Normal (6px)
Intense (12px)
<div class="shake-target" id="shake-subtle" style="background: #e3f2fd; color: #1565c0;">Subtle (2px)</div>
<div class="shake-target" id="shake-normal" style="background: #fff3e0; color: #8c2d00;">Normal (6px)</div>
<div class="shake-target" id="shake-intense" style="background: #fce4ec; color: #c62828;">Intense (12px)</div>
<button type="button" class="btn btn-primary" id="shake-start-subtle">Subtle</button>
<button type="button" class="btn btn-warning" id="shake-start-normal">Normal</button>
<button type="button" class="btn btn-danger" id="shake-start-intense">Intense</button>
/**
 * Demo: Intensity Levels - from public/showcase/effects/shake.
 */
export function mount(root) {
        // Demo 2: Intensity
    $(root).find('#shake-start-subtle').on('click', () => {
          Domma.effects.shake('#shake-subtle', {
            intensity: 2,
            respectMotionPreference: false
          });
        });
    $(root).find('#shake-start-normal').on('click', () => {
          Domma.effects.shake('#shake-normal', {
            intensity: 6,
            respectMotionPreference: false
          });
        });
    $(root).find('#shake-start-intense').on('click', () => {
          Domma.effects.shake('#shake-intense', {
            intensity: 12,
            respectMotionPreference: false
          });
        });
}
Domma.effects.shake('#el', { intensity: 2 });   // Subtle
Domma.effects.shake('#el', { intensity: 6 });   // Normal (default)
Domma.effects.shake('#el', { intensity: 12 });  // Intense

Demo: Form Validation

Shake invalid form inputs to draw attention. Try submitting with an empty or invalid email.

Demo: Form Validation
<label class="d-block mb-2 font-semibold">Email Address</label>
<input type="email" class="shake-input mb-2" id="shake-email" placeholder="Enter your email">
<div class="text-danger mb-3" id="shake-error" style="display: none; font-size: 0.9rem;">Please enter a valid email address.</div>
<button type="button" class="btn btn-primary" id="shake-validate">Submit</button>
/**
 * Demo: Form Validation - from public/showcase/effects/shake.
 */
export function mount(root) {
        // Demo 3: Form Validation
    $(root).find('#shake-validate').on('click', () => {
          const email = $(root).find('#shake-email').val();
          const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);

          if (!isValid) {
            $(root).find('#shake-email').addClass('invalid');
            $(root).find('#shake-error').show();
            Domma.effects.shake('#shake-email', {
              intensity: 4,
              duration: 400,
              respectMotionPreference: false,
              onComplete: () => {
                setTimeout(() => {
                  $(root).find('#shake-email').removeClass('invalid');
                  $(root).find('#shake-error').hide();
                }, 2000);
              }
            });
          } else {
            $(root).find('#shake-email').removeClass('invalid');
            $(root).find('#shake-error').hide();
            E.toast('Valid email!', { type: 'success' });
          }
        });
}
$('#submit').on('click', () => {
  const email = $('#email').val();
  const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);

  if (!isValid) {
    $('#email').addClass('invalid');
    Domma.effects.shake('#email', {
      intensity: 4,
      duration: 400,
      onComplete: () => {
        // Remove invalid state after delay
        setTimeout(() => $('#email').removeClass('invalid'), 2000);
      }
    });
  }
});

Demo: Multiple Iterations

Repeat the shake cycle multiple times for persistent emphasis.

Demo: Multiple Iterations
Shake Me!
<div class="shake-target bg-warning text-dark" id="shake-iter">Shake Me!</div>
<button type="button" class="btn btn-primary" id="shake-1x">1x</button>
<button type="button" class="btn btn-primary" id="shake-2x">2x</button>
<button type="button" class="btn btn-primary" id="shake-3x">3x</button>
/**
 * Demo: Multiple Iterations - from public/showcase/effects/shake.
 */
export function mount(root) {
        // Demo 4: Iterations
    $(root).find('#shake-1x').on('click', () => {
          Domma.effects.shake('#shake-iter', {
            iterations: 1,
            respectMotionPreference: false
          });
        });
    $(root).find('#shake-2x').on('click', () => {
          Domma.effects.shake('#shake-iter', {
            iterations: 2,
            respectMotionPreference: false
          });
        });
    $(root).find('#shake-3x').on('click', () => {
          Domma.effects.shake('#shake-iter', {
            iterations: 3,
            respectMotionPreference: false
          });
        });
}
Domma.effects.shake('#el', { iterations: 1 }); // Default
Domma.effects.shake('#el', { iterations: 2 });
Domma.effects.shake('#el', { iterations: 3 });

Demo: Staggered Shake

Shake multiple elements with a cascading delay.

Demo: Staggered Shake
Item 1
Item 2
Item 3
Item 4
<div class="shake-target shake-stagger" style="background: #e8eaf6; color: #283593;">Item 1</div>
<div class="shake-target shake-stagger" style="background: #e8eaf6; color: #283593;">Item 2</div>
<div class="shake-target shake-stagger" style="background: #e8eaf6; color: #283593;">Item 3</div>
<div class="shake-target shake-stagger" style="background: #e8eaf6; color: #283593;">Item 4</div>
<button type="button" class="btn btn-primary mt-3" id="shake-start-stagger">Shake All (Staggered)</button>
/**
 * Demo: Staggered Shake - from public/showcase/effects/shake.
 */
export function mount(root) {
        // Demo 5: Stagger
    $(root).find('#shake-start-stagger').on('click', () => {
          Domma.effects.shake('.shake-stagger', {
            stagger: 100,
            intensity: 5,
            direction: 'horizontal',
            respectMotionPreference: false
          });
        });
}
Domma.effects.shake('.item', {
  stagger: 100,
  intensity: 5,
  direction: 'horizontal'
});

Options Reference

Option Type Default Description
intensity number 6 Shake distance in pixels
duration number 500 Total shake duration in ms
direction string 'horizontal' 'horizontal', 'vertical', 'both'
easing string 'ease-in-out' CSS easing function
iterations number 1 Number of shake cycles
stagger number 0 Delay between elements (ms)
respectMotionPreference boolean true Honour prefers-reduced-motion
onComplete function null Callback when shake completes