Repository navigation
feat(data-table): inline cell editing #560
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
itsprade
wants to merge
16
commits into
main
Choose a base branch
from
feat/core/1750-datatable-inline-edit
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
6df0b3b
docs(data-table): propose inline cell editing
itsprade 2d2f81f
feat(data-table): add cell edit rules and keyboard navigation helpers
itsprade 3182fdb
feat(data-table): inline cell editing for text, number, money and lin…
itsprade cb1e072
docs(data-table): document inline editing and add a goods-receipt demo
itsprade 181871b
feat(data-table): dropdown, badge and date cell editors
itsprade 1408647
fix(data-table): address pre-push review of inline editing
itsprade 4e4f7f2
feat(data-table): spreadsheet-style editable cells
itsprade dd93733
fix(data-table): open an empty bounded calendar on a pickable month
itsprade 50d4729
docs(data-table): more inline-editing examples in the lab demo
itsprade 3185e7e
feat(data-table): keep a space for dropdown and date icons
itsprade e7b094f
fix(select): add inner padding to the dropdown
itsprade 40d8ebd
docs(data-table): note in the decision record that PR 2 is folded in
itsprade f5ab575
Merge origin/main into feat/core/1750-datatable-inline-edit
itsprade 65d5dd2
feat(data-table): act on the first review's experience calls
itsprade 3c6a96f
Merge remote-tracking branch 'origin/main' into feat/core/1750-datata…
Copilot c7c4d22
fix(data-table): align inline date picker with merged timezone rendering
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| --- | ||
| "@tailor-platform/app-shell": minor | ||
| --- | ||
|
|
||
| Add inline cell editing to `DataTable`. Give a typed column an `edit` config and users can change its values right in the list: `text`, `number` and `money` cells are typed into; `text` / `link` columns with `edit.options` and `badge` columns become dropdowns you can type into to search; `date` columns open a calendar. Editable columns show a pen after their title, and each cell shows a pen, chevron or calendar icon on hover. Rules (`min`, `max`, `maxDecimals`, `required`, `validate`) are checked when the user saves; a value that breaks one stays on screen, outlined in orange, and is never saved until it's fixed or undone. Per-row control (`canEdit(row, { selected })`) and Enter / Tab keyboard entry come built in. The value reaches `edit.onCommit(row, value)` when the user leaves the cell or picks a choice; return a promise to autosave, and the cell reverts if it rejects. Leaving the page with unsaved edits asks first. | ||
|
|
||
| ```tsx | ||
| column({ | ||
| id: "received", | ||
| label: "Received", | ||
| type: "number", | ||
| edit: { | ||
| canEdit: (row, { selected }) => selected, | ||
| min: 0, | ||
| maxDecimals: 0, // whole numbers only | ||
| onCommit: (row, value) => updateLine(row.id, { received: value }), | ||
| }, | ||
| }); | ||
|
|
||
| column({ | ||
| id: "supplierId", | ||
| label: "Supplier", | ||
| type: "text", | ||
| edit: { | ||
| options: suppliers.map((s) => ({ value: s.id, label: s.name })), | ||
| onCommit: (row, value) => updateLine(row.id, { supplierId: value }), | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| Also fixes date display: a date-only `"YYYY-MM-DD"` value now shows that day in every time zone instead of the day before west of UTC. A `number` / `money` column with `edit.maxDecimals` displays up to that many decimals, and a `number` column whose `maxDecimals` is below its `minDecimals` no longer throws. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@tailor-platform/app-shell": patch | ||
| --- | ||
|
|
||
| `Select`'s dropdown now has a 4px inner gap, like `Menu`, `Combobox` and `Autocomplete`, so the highlighted option no longer touches the dropdown's edges. |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we avoid exposing
min,max,maxDecimals,required, and a separatevalidatecallback here?I would prefer
edit.schemato accept a Standard Schema-compatible validator, following the existingCsvImporterpattern. That gives consumers one validation and normalization point, rather than adding DataTable-specific validation rules as public API.For example, using Zod purely as a Standard Schema-compatible implementation (DataTable itself would not need a Zod dependency):
The same mechanism can normalize a value before it is committed:
I think the table should keep the raw draft untouched while the user is typing, then parse it for the column type and run the schema on Enter, Tab, or blur. On success, it should commit the schema output; on failure, it should leave the external value unchanged and surface the schema issue. In particular, we should not transform on every keystroke, since that tends to break IME composition and cursor position.
Before settling that contract, I think we should explicitly resolve the following:
onCommit/server failure means “the value could not be saved.” These should not be presented as the same state.row. If row-dependent rules remain supported, we need to decide how that context reaches the schema (for example,schema: (row) => schema).aria-invalid, and an associated accessible error description.This is a larger API decision than replacing
validate, but I think it produces a cleaner and more reusable public contract than adding the individual options.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think an as-you-type filter – for e.g., to not allow a-z for numeric inputs – makes sense.
I think we treat empty as a value. If the field is optional, this sets the field to null or empty-string. If the field is required, then it is a validation error
"Enter/Tab should only move after the latest successful validation" — I like this! (Although if it is async and takes some time, this would add a lot of friction)
This live inline editing is not an easy thing it seems. Would saving a field at a time be the wisest here: If I want to update the Order Date of a PO, then we only update that single field. Locking the whole row until the save finishes would be a poor user experience
For reference, here is Google Sheets with a validation error
and AirTable

I still have reservations about live-inline cell editing. A save button to commit the changes to me is a much simpler task, with a lot less prickly UX edges