Source Code

<div class="container py-5 d-flex justify-content-center">
  <div class="card bscell-card">
    <div class="card-body p-3">
      <h6 class="fw-bold mb-2">Inventory</h6>
      <table class="table table-sm align-middle mb-0">
        <thead><tr><th>Item</th><th>Qty</th><th>Unit price</th></tr></thead>
        <tbody id="bscellBody"></tbody>
      </table>
      <p class="small text-muted mt-2 mb-0">Click Qty or Unit price to edit. Enter saves, Escape cancels.</p>
    </div>
  </div>
</div>

Bootstrap Inline Table Cell Editing — Free HTML CSS JS Snippet

Bootstrap Inline Table Cell Editing · Tables · Plain HTML, CSS & JS · Live preview

What's included

Features

Editing reads the real underlying numeric value from the data array, never a formatted display string
Enter, blur, and Escape all funnel through one commit() function with a single save/discard branch
Invalid input (NaN or negative) is silently rejected, keeping the previous valid value instead
Price values are rounded to two decimals on save, avoiding floating-point display artifacts
The input is focused and pre-selected the instant editing starts, ready for immediate typing

About this UI Snippet

Bootstrap Inline Table Cell Editing — HTML, CSS & JavaScript

Screenshot of the Bootstrap Inline Table Cell Editing snippet rendered live

Editing happens entirely inside the clicked <td>startEdit() reads the row's current raw numeric value directly from the rows data array (not by parsing the displayed, already-formatted "$39.00" text back out of the DOM), swaps the cell's content for a real number input pre-filled with that value, and focuses and selects it so typing immediately replaces the old value.

commit(save) is the single function both the blur listener and the keydown handler funnel through — blurring the input (clicking away) and pressing Enter both save, while Escape calls commit(false), which re-renders without touching rows at all, discarding whatever was typed. Centralizing both outcomes in one function is what guarantees "save" always means the same thing regardless of which path triggered it.

A save is only actually applied when the parsed value passes !Number.isNaN(parsed) && parsed >= 0 — typing garbage or a negative number into the cell and pressing Enter silently keeps the row's previous value rather than corrupting it with NaN or a nonsensical negative quantity, and price values are additionally rounded to two decimal places to avoid accumulating floating-point artifacts like 24.500000000000004.

A committed flag guards commit() against running twice for a subtle reason: render() removes the <input> from the DOM, and removing a focused element from the DOM itself fires a native blur event on it. Without the guard, pressing Escape would discard the edit, re-render, and then that synthetic blur would immediately fire commit(true) a second time with the same stale input value — silently overwriting the discard with an unwanted save a moment later.

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 inline validation styling (a red outline) that appears live while an invalid value is typed, before the user even tries to save, or to add support for editing a text field (like the item name) alongside the existing numeric fields, using a text input instead of a number input.

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 table with inline, click-to-edit cells, using the real Bootstrap CDN framework (bootstrap.min.css and bootstrap.bundle.min.js), not custom CSS made to resemble it.

Requirements:
- A table with at least 3 rows and at least two numeric editable columns (e.g. quantity and price), backed by a plain JavaScript array of row objects holding the real numeric values.
- Clicking an editable cell replaces its content with a real number input pre-filled with that field's actual underlying value (not a value parsed back out of the formatted display text), focused and with its text selected.
- Pressing Enter or blurring the input (clicking elsewhere) must save the edit; pressing Escape must discard it — all three paths should funnel through one shared commit function with a single save/discard branch, not duplicated logic per trigger.
- A save must be rejected (keeping the cell's previous value) if the entered value is not a valid non-negative number. Price values should be rounded to two decimal places on save to avoid floating-point display artifacts.

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 snippetA three-row inventory table shows, with Qty and Unit price cells styled as clickable.
  2. 2
    Click a Qty cellIt becomes a real number input, pre-filled and already selected, ready to type over.
  3. 3
    Type a new number and press EnterThe cell saves and reverts to plain text showing the new value.
  4. 4
    Click a price cell, type a new value, and click elsewhere on the pageBlurring the input also saves, exactly like pressing Enter does.
  5. 5
    Click a cell, type something, then press EscapeThe edit is discarded and the cell reverts to its previous, unchanged value.
  6. 6
    Try entering a negative number or clearing the field entirelyThe cell keeps its last valid value rather than accepting invalid input.

Real-world uses

Common Use Cases

Inventory, pricing, and spreadsheet-style admin tables
Pairs with bootstrap-sortable-data-table for a fuller editable data grid.
Order and quote line-item editors
Adjust a quantity or price directly in a table row without opening a separate edit form.
DEV
Internal admin tools managing structured records
A fast way to correct individual field values without a full record-edit modal for a single-number change.

Got questions?

Frequently Asked Questions

Directly from the underlying rows data array (row.qty or row.price), never by parsing the displayed, already-formatted cell text — this avoids re-parsing a "$39.00" string back into a number, which is both unnecessary and error-prone.

The parsed value fails the !Number.isNaN(parsed) && parsed >= 0 check inside commit(), so the save is silently skipped and the cell reverts to its last valid value rather than accepting invalid data.

It saves — the blur event calls commit(true), the same as pressing Enter; only pressing Escape explicitly discards the edit via commit(false).

Yes. Track which cell (row id + field) is currently being edited in component state, conditionally render an input or plain text per cell based on that state, and validate/commit the parsed value the same way on blur, Enter, or Escape.