ReoGrid ReoGrid Web

Form Mode

A common way to use a spreadsheet in a business app is not as a spreadsheet at all: the layout is fixed, most cells are protected, and the user only fills values into a handful of boxes. Since v1.6.0 four worksheet switches cover that shape directly. Available in both editions.

All four are render and interaction settings only — none of them is stored in xlsx or JSON, so re-apply them after loadJson or reset.

const ws = grid.worksheet

ws.layoutLocked = true
ws.clickToEdit = true
ws.formNavigation = true
ws.setCellPlaceholder(2, 1, 'e.g. Taro Yamada')

Lock the layout

ws.layoutLocked = true

Stops the user changing the layout: header drag-resize of column widths and row heights, the resize cursor, double-click auto-fit, and whole-row / whole-column reorder drags are all disabled at once.

Sizing from the API still works, so your own template code is unaffected:

ws.column(1).width = 180   // still applies

Open the editor on one click

ws.clickToEdit = true

An editable cell enters edit mode on a single click — no double-click — with the caret at the end of the existing text, and the pointer shows an I-beam over such cells so it looks like the input it behaves as.

Protected cells are unaffected, and so are cell types that replace the text (checkbox, and friends) — those keep their click behaviour.


Placeholder hints

ws.setCellPlaceholder(2, 1, 'e.g. Taro Yamada')

ws.getCellPlaceholder(2, 1)        // 'e.g. Taro Yamada' | null
ws.getCellPlaceholderEntries()     // [{ row, column, text }, …]
ws.clearCellPlaceholders()

Draws muted hint text in an empty cell, like an HTML input’s placeholder. It:

  • stays inside the cell — it never spills into the neighbour,
  • is never right-aligned as a number,
  • is never part of the cell value, and never appears in PDF, print, xlsx or JSON,
  • shifts with row and column inserts and deletes, the way comments do.

Pass an empty string to remove one.


Walk the input cells with Enter and Tab

ws.formNavigation = true

Enter and Tab commit the cell and move to the next input cell, opening the editor there with its text selected. Shift reverses the direction.

The built-in order is a reading-order scan over editable cells that:

  • skips protected cells,
  • skips hidden rows and columns,
  • treats a merged block as one stop, at its anchor,
  • wraps at the end of a row — so the last field of a row continues into the first field of the next one.

That is what makes a form fill in end-to-end without ever reaching for the mouse.

A tab order of your own

When the app knows its own layout — a fixed report template, say — install a navigator to walk the fields deliberately and skip editable cells that are not part of the form:

const order = [
  { row: 2, column: 1 },
  { row: 2, column: 4 },
  { row: 4, column: 1 },
]

ws.setFormNavigator((from, direction) => {
  const i = order.findIndex(c => c.row === from.row && c.column === from.column)
  return order[i + direction] ?? null   // null = stop at the end of the form
})

// Back to the built-in scan
ws.setFormNavigator(null)

Returning null commits the value and stays put, which is what you want at the end of a form.

To ask where navigation would go without moving:

const next = ws.nextInputCell(2, 1, 1)   // +1 forward, -1 backward

List validation from the keyboard

Data-validation list rules can now be driven entirely from the keyboard, which is what makes a dropdown field part of the same flow:

KeyAction
while editingOpens the dropdown
Alt+↓ while the cell is selectedOpens the dropdown
↑ / ↓ while openMoves through the options
EnterCommits the highlighted option
EscapeCloses without choosing

The list opens at the current value (or the first entry when the cell is empty), so ↓ then Enter is a two-keystroke pick. The choice is committed through the editor, so validation rules and form navigation both still apply.


Putting it together

const ws = grid.worksheet

// 1. Protect everything, then unlock the input cells
ws.protected = true
ws.range('C3:C8').setLock('unlocked')

// 2. Form behaviour
ws.layoutLocked = true
ws.clickToEdit = true
ws.formNavigation = true

// 3. Hints
ws.setCellPlaceholder(2, 2, 'e.g. Taro Yamada')
ws.setCellPlaceholder(3, 2, 'e.g. 03-1234-5678')

// 4. A dropdown field
ws.range('C5').setValidation({ type: 'list', options: ['Tokyo', 'Osaka', 'Nagoya'] })

The user clicks the first box, types, presses Enter, and walks the whole form to the end.


Not persisted

layoutLocked, clickToEdit, formNavigation, the installed navigator and every placeholder are screen state. They are not written to xlsx or ReoGrid JSON, and a loadJson() or reset() clears them — re-apply them from the host afterwards.


  • Form mode demo — an application form you can fill in without touching the mouse.
  • Protection — cell lock state and sheet protection, which decide what counts as an input cell.
  • Data Validation — list rules and the dropdown.
  • Cell Editor — editor behaviour and keyboard focus.
  • Report Binding — materializing the template a form fills in.
Was this page helpful?
Stay Updated

Be first to know — get updates as they ship

Get notified of new releases, features, and announcements.
No spam — just updates that matter.