Source Code

<div class="container py-5 d-flex justify-content-center">
  <div class="card bsauto-card">
    <div class="card-body p-4">
      <div class="d-flex justify-content-between align-items-center mb-2">
        <h5 class="fw-bold mb-0">Untitled note</h5>
        <span class="small d-flex align-items-center gap-2" id="bsautoStatus">
          <span class="bsauto-dot bsauto-dot-idle" id="bsautoDot"></span>
          <span id="bsautoText">All changes saved</span>
        </span>
      </div>
      <textarea class="form-control" id="bsautoBody" rows="6" placeholder="Start typing...">Q3 planning notes — revisit budget line items before Thursday's review.</textarea>
      <p class="small text-muted mt-2 mb-0">Autosaves 1.2s after you stop typing.</p>
    </div>
  </div>
</div>

Bootstrap Form Autosave Status — Free HTML CSS JS Snippet

Bootstrap Form Autosave Status · Forms · Plain HTML, CSS & JS · Live preview

What's included

Features

Debounced saves — one request per pause in typing, not one per keystroke
isSaving guard prevents two overlapping save requests from ever firing at once
A queued pendingResave flag guarantees a keystroke during a save is never silently lost
A real, changing timestamp on every successful save, not a static label
A simulated failure path with a working Retry action wired to the same save function
Four distinct visual states (idle, saving, saved, failed) driven by one setState function

About this UI Snippet

Bootstrap Form Autosave Status — HTML, CSS & JavaScript

Screenshot of the Bootstrap Form Autosave Status snippet rendered live

Autosave has a timing problem most demos skip: firing a save on every keystroke would flood a real backend, but waiting until the user is completely done is exactly what a "Save" button already does. This snippet uses a debounce — every input event clears the previous setTimeout and starts a new 1200ms one — so performSave() only actually runs once typing genuinely pauses, no matter how fast or long the user types before that.

The part most autosave demos skip entirely is what happens when a save is still in flight and the user keeps typing. This snippet guards performSave() with an isSaving flag: a keystroke that lands mid-save doesn't fire a second overlapping request, it just sets a pendingResave flag that triggers exactly one more save the moment the current one resolves — so the saved copy can never silently fall behind the last thing the user typed, and the backend never sees two requests racing each other.

The failure path is simulated with a random 15% chance specifically so the Failed state and its Retry link are actually reachable in this preview rather than only existing in the code. Retry calls the exact same performSave() function a fresh debounce would have called, so there's no separate "retry logic" to keep correct alongside the main save path.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Hand this snippet to an AI coding assistant like Claude and ask it to add exponential backoff to the Retry flow (waiting longer between each failed attempt) or to persist the draft to localStorage as a fallback whenever every retry fails, so a page refresh never loses unsaved text.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a Bootstrap 5.3 form autosave status indicator, using the real Bootstrap CDN framework (bootstrap.min.css and bootstrap.bundle.min.js) for the surrounding card, not custom CSS made to resemble it.

Requirements:
- A card with a textarea and a small status indicator (a colored dot plus text) showing one of: idle/unsaved, saving, saved, or failed.
- Debounce saves: every input event should reset a timer, and the actual save function should only run once typing has paused for about 1.2 seconds.
- The save function must guard against overlapping calls with an isSaving flag — if a new save is requested while one is already in progress, queue exactly one follow-up save to run immediately after the current one resolves, rather than firing a second request or dropping the request entirely.
- Simulate the save with a randomized outcome so both success and failure are reachable: on success, show "Saved at" plus the current time; on failure, show an inline Retry action that calls the same save function.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Load the snippetThe status reads "All changes saved" with a gray idle dot.
  2. 2
    Start typing in the textareaThe status immediately switches to "Unsaved changes..." on the very first keystroke.
  3. 3
    Keep typing, then pause1.2 seconds after your last keystroke, the dot turns amber and pulses while "Saving..." shows.
  4. 4
    Wait for the save to resolveRoughly 85% of the time it turns green with a real timestamp; the rest of the time it turns red with a Retry link.
  5. 5
    Click Retry on a failureIt re-runs the same save logic and usually succeeds on the next attempt.
  6. 6
    Type again while a save is in progressNo second "Saving..." flicker appears mid-save — one more save is queued and runs immediately after the first finishes.

Real-world uses

Common Use Cases

Notes, docs, and long-form content editors
Removes the need for an explicit Save button entirely — pairs well with bootstrap-inline-form-editing for settings that should feel just as continuous.
Admin panels editing structured records
Show the same status pattern next to any field group in a CMS or dashboard record editor.
Learning debounce and request-overlap handling
A compact, realistic example of the two problems every autosave implementation has to solve, in isolation from a specific backend.
SEARCH
Search-as-you-type and live filter inputs
The same debounce-plus-in-flight-guard pattern applies directly to any input that triggers a network request as the user types.

Got questions?

Frequently Asked Questions

It is long enough that normal typing does not trigger a save mid-sentence, but short enough that a genuine pause reads as "done for now" rather than a stall. Tune it to match how expensive your real save operation is.

A brand-new debounce timer starts from that keystroke, exactly as if no previous save had happened — the finished save does not interfere with the next one.

A real save is usually a network request; firing one per keystroke on a paragraph of typing would send dozens of requests for a single sentence, most of which are immediately superseded by the next one.

Yes. In React, keep isSaving and the debounce timer in refs (not state, since updating them should not trigger a re-render) and drive the visible state through useState; the same performSave logic works unchanged.

Replace the setTimeout inside performSave with an actual fetch/axios call, treating its resolved promise as success and its rejection (or a non-2xx response) as the failure branch — the debounce and overlap-guard logic around it needs no changes.