---
title: Tables, search, and modals
order: 5
updated: 2026-07-12
---

# Tables, search, and modals

Almost every list in the app — enquiries, customers, products, stock, expenses, purchase orders — is drawn with the **same** table component, searched with the same kind of search box, and edited through the same modal system. The individual screens differ in *what* they show, but the mechanics on this page are shared, so learning them once means you know them everywhere.

This page covers the parts that behave identically across the whole app: the table (its columns, the *#* column, show/hide/reorder, row actions, expandable rows), the right-click menu, search boxes, pagination, and the modal/confirmation system.

## The shared table

A list is drawn as a table with a header row at the top and one `<row>` per record below. Every table shares the same anatomy:

- A left-most *#* column (the serial number).
- One column per field the screen chose to show.
- Optionally, an expand arrow on the right for rows that carry a detail panel.

Rows are shown exactly in the order the screen sent them — the table does **not** re-sort rows when you click a header (see [Can I sort by clicking a column header?](#can-i-sort-by-clicking-a-column-header)). To change the order or narrow the list, use that screen's search box and filters.

### The *#* column

The first column is a running serial number, printed zero-padded to at least two digits (`01`, `02`, … `09`, `10`).

- On a paginated list the count **keeps going across pages** — it does not restart at `01` on page 2. With 20 rows per page, page 2 starts at `21`, so a given row keeps the same number no matter which page you are viewing. (The exact rows-per-page is decided by each screen; 20 is the common value but it is not universal.)
- On tables whose rows can be expanded, the *#* header doubles as an **expand-all / collapse-all** toggle. Hover it and the `#` glyph underlines to show it is clickable; click it to open every row's detail panel at once, click again to close them all. On tables without expandable rows the *#* is just a label and does nothing.

### Columns and alignment

Each column has a fixed heading (shown in `UPPERCASE`) and a set alignment — most columns read left-aligned, and the last column of a multi-column table is right-aligned by default (screens can override the direction per column). Column contents never wrap; a very wide table scrolls sideways inside its own rounded container rather than pushing the page sideways.

### Show, hide, and reorder columns

Screens that offer column control show a *Toggle Columns* control — usually a small outline button with a sliders icon, or a *Toggle Columns* row (sub-titled *Show, hide or reorder table columns*) inside that screen's options menu. Opening it reveals a *Columns* panel where you can:

- **Tick / untick** a column to show or hide it. Ticking is a live multi-select — the table updates immediately.
- **Drag** a column up or down by its grip handle to reorder it. The table's column order follows your drag.
- **Reset** — the *Reset* link (with a circular-arrow icon) in the panel header restores that table's original columns and order.

Some columns are structural (for example an actions / open column) and never appear in this list — they stay pinned in place and always visible.

**Your choices are remembered per table, per device.** Show/hide and column order are saved in that browser's local storage (under the key `__table_ctrl__`), keyed by the individual table, so the enquiry list and the customer list each keep their own layout. Because it is stored in the browser, your layout does not follow you to another computer or to the desktop app, and clearing site data resets every table to defaults. Which columns are visible and their order are saved; row data, which rows are expanded, and the *#* serial are not.

If a brand-new column is added to a screen in an update, it is merged into your saved layout at the end (and shown if it is a default-visible column) without discarding your existing arrangement.

### Expandable rows

On some lists a row carries a detail panel — click the down-arrow at the right of the row (or, on screens that opt in, click anywhere on the row) to slide it open, and click again to collapse it. The *#* header expands or collapses every row at once, as described above. Expansion is view-only and is not saved; reloading the screen starts with rows collapsed unless the screen deliberately opens them by default.

### Loading and empty states

- While a list is fetching, the table shows shimmering **skeleton rows** in place of data. It keeps roughly the same number of rows it last showed, so a refresh does not visibly jump in height.
- When a list genuinely has no records, the table shows a single centred message (for example *No data yet.*) instead of an empty grid. If you searched or filtered and got this, widen your search rather than assuming the list is broken.

## Row actions and the right-click menu

The app has one global right-click menu, and it does several jobs at once depending on where you click.

### Actions on a row

Right-clicking a row opens the context menu with the actions that screen registered for *that* row — open, edit, send, delete, and so on. The exact set depends on the screen and on your permissions; an action you are not allowed to run is either hidden or shown greyed-out. Some screens **also** expose an inline actions menu (a small button on the row itself) that lists the same actions, for people who prefer not to right-click.

Menu items can carry a short description under their label and can nest into sub-menus (a parent item with a chevron opens a further list). Disabled items are shown but not clickable.

### Text and navigation actions

The same right-click menu always offers general helpers, so you never need the browser's own menu:

- **Copy** appears whenever you have text selected — inside a field *or* just highlighted on the page (a table cell, a heading, a paragraph).
- **Copy**, **Cut**, **Paste**, and **Select All** appear when you right-click inside an editable field (an input, a text area, or a rich-text editor).
- A **spell-check** entry appears when you right-click a single word in an editable field: a correctly spelled word shows a quiet *✓ ok*, a misspelled one shows *misspelled* with a sub-menu of suggested corrections (click one to replace the word in place). Very long words (over 16 characters) are flagged without suggestions.
- **Back**, **Forward**, and **Reload** are always present at the bottom, mirroring the browser's own navigation.

## Search

Most lists have a search box at the top. What each box matches is decided by the screen — for example the customer list's *Search customers…* matches the customer name — so the same-looking box searches different fields on different screens.

- Typing narrows the list to records that match. Search boxes that hit the server debounce your typing, so results catch up a moment after you stop — you do not need to press Enter.
- When a list also exposes **filters** (a date range, a status, a supplier, and so on, often behind an *Advanced Search* entry in the options menu), the filters apply **on top of** whatever you typed. Search and filter narrow together, not separately.
- Autocomplete-style pickers (choosing a customer, product, or contact person inside a form) use the same search-as-you-type behaviour and load more results as you scroll.

Everything you type is re-checked by the server when it returns results, so a malformed or oversized search can never break the list — at worst it simply finds nothing.

## Pagination

Long lists — enquiries, orders, expense ledgers — are split into pages with a pager at the bottom: *Previous*, numbered page links, and *Next*. Lists whose results are naturally short show no pager at all.

- The current page is highlighted. *Previous* is disabled on page 1 and *Next* on the last page.
- On lists with very many pages the pager stays compact by showing the first and last page and a small window around the current page, collapsing the rest to an ellipsis (`…`) — for example `1 … 4 5 6 … 42`.
- Because the *#* column counts across pages, a row's number tells you its overall position, not its position on the current page.

## Modals

Many actions open a **modal** — a panel that floats in the centre of the screen with the page dimmed (and blurred) behind it — instead of taking you to a new screen, so you never lose your place. Modals are used for forms, confirmations, detail views, and even for opening whole pages on top of the current one.

### Opening and closing

- Close a modal with the close button in its corner, with the *Cancel* button where one is provided, by clicking the dimmed area outside it, or by pressing `Esc`.
- Clicking outside and pressing `Esc` only act on the **top-most** modal, and a modal can be built to opt out of either (a form mid-edit may refuse to close on a stray outside-click, for example) — in that case use its own close or *Cancel* button.
- The browser/desktop **Back** action closes the open modal instead of leaving the screen. So *Back* backs you out of a stacked modal one layer at a time, and only leaves the page once no modal is open.

### Stacking and opening pages as modals

You can open one modal on top of another — for instance opening a linked enquiry from inside another record. Each new layer stacks over the last, and closing the top layer returns you to the one beneath. A page opened this way fills most of the screen (a large "cover" modal) but is still just a modal: closing it drops you back exactly where you were. (See [Finding your way around](/docs/getting-started/navigating) for how deep stacking behaves.)

This is the same dual-mode plumbing throughout the app — on the desktop app a page opened as a modal is loaded eagerly, and on the web it is lazy-loaded with a brief loader — but as a user you see the same panel either way.

### Animations

Modals fade and slide in by default. If you have turned on the low-device / reduced-animation preference, they appear without the motion to stay snappy on slower machines.

## Confirmations and warnings

The app never silently deletes or destroys a record. A destructive action opens a **confirmation modal first** that spells out what is about to happen, with a *Cancel* button and a separate danger-coloured confirm button (often alongside a warning icon). Read it before clicking through — the action is hard to undo afterwards.

Confirmation dialogs are one of the few places that deliberately keep a *Cancel* button; most ordinary modals rely on the close button and outside-click instead. Whatever the confirmation warns you about, the server independently re-checks that the action is allowed and valid before carrying it out — the dialog is the courtesy, not the only guard.

## Common questions

### Why is a button or menu item greyed out?

Either the action does not apply to that row in its current state, or you do not have permission for it. Hover for a tooltip. Permissions are set under *Settings → Users & Permissions* — ask your administrator if you think you should have access.

### Can I sort by clicking a column header?

No — clicking a header does not re-sort the rows. The table shows rows in the order the screen provides them. To change what you see, use the screen's search box and its filters (date range, status, and so on); to change the *order of the columns themselves*, drag them in *Toggle Columns*.

### I hid a column by mistake — how do I get it back?

Open *Toggle Columns* and tick it again, or use *Reset* in that panel to restore the table's original columns and order. Column layout is saved per table.

### My column layout is different on another computer — why?

Column show/hide and order are saved in the browser you set them in, not on your account, so they do not travel between computers or between the web app and the desktop app. Clearing the browser's site data also resets every table to its defaults.

### How do I refresh a list?

Most lists refresh on their own after you make a change. To force a refresh, use *Reload* from the right-click menu, switch to another module and back, or reload the page. Some screens also put a *Refresh* entry in their options menu.

### Why did pressing Back not leave the screen?

If a modal was open, *Back* closes that modal first (one layer per press). Once every modal is closed, *Back* leaves the screen as usual.

### The list is empty but I know there are records — what happened?

You are probably still inside a search or filter. Clear the search box and reset any active filters (date range, status, supplier). If a whole module is missing from the sidebar instead, you have not been granted permission for it — see [Finding your way around](/docs/getting-started/navigating).

### Where do I set which columns a printed document shows?

Table columns on screen are separate from the columns printed on quotations, purchase orders, and receipts. Print-column choices live under *Settings → Personalisation* — see [Personalisation](/docs/settings/personalisation) and [Document templates](/docs/settings/document-templates).
