Hover✨ Premium

Submit Button

A submit button that morphs into a circular spinner during loading, then into a confirmation checkmark — three sequential shape states in CSS and JavaScript, with no page reload.

CSSJSStates

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Hover has 48 effects, including 5 free. Explore the category →

3 usage examples

Submitting a contact form — website of a dental practice — Submit Button example 1

① Submitting a contact form — website of a dental practice

WhenSend my request button below the appointment request form; on click the button morphs into a spinner then confirms with a green checkmark. 220×48 px button.
WhyA button that visually tracks submission progress reassures the patient waiting for appointment confirmation, without resorting to an intrusive loading popup.
Settings220×48 px button, background turns health-green on success, a Your request has been sent label shown beside it after success.
Submitting an online quote — custom shutter configuration tool for a joinery manufacturer — Submit Button example 2

② Submitting an online quote — custom shutter configuration tool for a joinery manufacturer

WhenFinal step of the configurator: Validate my order button; the loading animation shows the quote is being calculated.
WhyA button that morphs into a spinner localizes the wait on the submission element and avoids a full-screen loading overlay.
SettingsLabel changes to Calculating… during loading (updated via JS before adding .loading), indigo background.
Creating an account on an amateur sports tournament platform — registration tool for sports associations — Submit Button example 3

③ Creating an account on an amateur sports tournament platform — registration tool for sports associations

WhenCreate my account button on the sign-up form; the morphing into a green checkmark confirms without an immediate redirect that the account was created.
WhyA visual confirmation on the button itself is tidier than a separate confirmation page for a lightweight action.
Settings200×48 px button, white spinner on violet background, white checkmark on green background at the success step.

How it works

The .fx-0363-root root (250 px tall, rgb(26, 26, 36) background) centers a .mi-submit-btn button (200×52 px). The button holds three stacked children: .mi-submit-text (the Send label), .mi-submit-loader (spinner container), and .mi-submit-check (checkmark SVG). In CSS, the .loading and .success states on the button drive three simultaneous changes: width (200 px → 52 px), border-radius (14 px → 26 px to form a circle), and each layer’s opacity.

The .mi-submit-spinner is a 24 px div with a border whose quarter is colored and the rest transparent; it rotates via @keyframes miSpinnerRot (0.8 s linear infinite). The checkmark is an SVG polyline whose path goes from 0% to 100% via stroke-dashoffset and @keyframes miCheckDraw (0.3 s). The shape transition lasts 0.4 s with ease-in-out; the checkmark transition starts 100 ms later so the morphing is complete when the check appears.

The script fires on button click, checks the button is not already loading or successful, adds .loading plus aria-busy="true" and aria-disabled="true". After 1 500 ms it removes .loading and adds .success. After another 1 800 ms it removes .success and clears the ARIA attributes. In a real integration, replace the fixed delays with your server call’s response.

Accessibility

  • Keyboard: the component is a real <button>; Tab reaches it, Space or Enter fires it. The loading state disables the button via aria-disabled to prevent double submissions.
  • Loading state announced: aria-busy="true" is added during loading. Screen readers that honor this attribute on a button announce that the action is in progress; test with NVDA and VoiceOver as implementations vary.
  • Reduced motion: under prefers-reduced-motion: reduce, the shape morphing (width and border-radius changes) is removed, the spinner animation stops, and the checkmark draw is instant. Loading and success states remain indicated by color changes and the spinner/checkmark appearing.
  • Touch: the button responds normally to touch events. Its 200×52 px target is wide and easy to hit with a finger.

Browser compatibility

CSS (transitions on width, border-radius, opacity, spinner and checkmark animations) + 0.5 KB of JavaScript (classList, setAttribute, setTimeout), no dependency. Verified in Chromium 151: 3-state morphing, aria-busy updated, two independent copies, reduced-motion without morphing, 0 errors. The preview captures show the animation auto-replayed by the scene code: this behaviour is not included in the sold code.

Chrome 49+✓ Full (measured)
Firefox 55+✓ Full
Safari 9+✓ Full
Edge 79+✓ Full (Chromium engine)
Mobile iOS 9+✓ Full
Android Chrome 49+✓ Full (Chromium engine)

Without JavaScript, the button is clickable but does not change state. Without CSS transitions, the three layers appear and disappear instantly with no morphing.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0363-root">
  <div class="mi-submit-scene">
    <button class="mi-submit-btn">
      <span class="mi-submit-text">Send</span>
      <span class="mi-submit-loader">
        <div class="mi-submit-spinner"></div>
      </span>
      <span class="mi-submit-check">
        <svg viewBox="0 0 24 24">
          <polyline points="20 6 9 17 4 12"></polyline>
        </svg>
      </span>
    </button>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Button color at rest (CSS — background on .mi-submit-btn) Violet #6366f1 Adapt to your brand’s primary color. The success color (.mi-submit-btn.success) and loading color (.mi-submit-btn.loading) can be changed independently.
Simulated loading duration (JS — first setTimeout) 1 500 ms In a real integration, replace the setTimeout with your network promise resolution: call the transition to .success in the .then() or success callback.
Button label (HTML — text in .mi-submit-text) Send Replace with Submit, Sign up, Confirm, etc. The morphing to a circle works regardless of label length since the starting width is fixed (200 px).
Checkmark display duration (JS — second setTimeout) 1 800 ms Reduce to 1 000 ms for a quick turnaround; increase to 3 000 ms to give the user time to read a confirmation message shown nearby.

FAQ

In the click handler, remove the setTimeout calls and fire your request (fetch, XMLHttpRequest). In the success callback, transition to .success; in the error callback, remove .loading and restore the button to its initial state, clearing aria-busy and aria-disabled too.
Yes. The script targets each .fx-0363-root independently. Each button has its own state cycle. Triggering a submission on one does not affect the others.
The script checks at the start of the click whether the button is already in .loading or .success: if so, the click is ignored. Combined with aria-disabled="true", this prevents multiple submissions during processing.