Turn repetitive row updates into a single click — ModifyRow, RunActions, conditional logic, canvas buttons, and Push Buttons that make your docs feel like applications.
Buttons require a human click. Automations (Lesson 13) run on their own when an event occurs. Both can execute the same actions — the difference is what starts them.
Two button placements in Coda: (1) a Button column in a table — every row gets its own clickable button, actions run in the context of that row. (2) A canvas button via /button — a global action with no specific row context, ideal for dashboard-level operations.
Add a Button column: click the + at the end of your column headers → choose Button. Then configure:
If(thisRow.[Done], "✓ Done", "Mark Done")Every row in the table gets its own instance of the button. Clicking a button in row 3 runs the action with thisRow set to row 3.
| Task | Status Select | Due Date Date | Action Button |
|---|---|---|---|
| Write landing copy | In Progress | Apr 20 | |
| Create Figma frames | To Do | Apr 25 | |
| Record demo video | Done | Apr 18 |
ModifyRow() is the workhorse action. It takes a row reference followed by column-value pairs. The row is almost always thisRow, but you can target any row — including a row in a different table.
thisRow — the row whose button was clicked. Can be any row reference.
[Status] — the column to update. Name in square brackets.
"Done" — the value to set. Can be a formula, not just a literal.
// Update the parent Project row's Last Updated field ModifyRow( Projects.Filter([Name] = thisRow.[Project Name]).First(), [Last Updated], Now() )
User() returns the currently logged-in user. Combine with ModifyRow to build lightweight approval trails: ModifyRow(thisRow, [Approved By], User(), [Approved At], Now()).
When one button needs to do more than one thing, wrap all actions inside RunActions(). Actions execute in the order listed. If any action fails, subsequent actions are skipped.
RunActions( // Step 1: update this row ModifyRow( thisRow, [Status], "Done", [Completed], Today() ), // Step 2: append a row to the Audit Log table AddRow( [Audit Log], [Event], "Completed: " & thisRow.[Name], [By], User(), [At], Now() ) )
RunActions() and runs them in order. Use the formula form when you need conditional branching: If(condition, RunActions(...), RunActions(...)).
Canvas buttons live on a page, not inside a table. Type /button anywhere on a canvas to insert one. Canvas buttons don't have thisRow context — there is no "current row" on a canvas. Use them for dashboard-level operations: "Add New Project", "Run Weekly Report".
AddRow(Projects, [Status], "To Do", [Created By], User()) — no thisRow needed, the target table and column values are specified explicitly.
Push Buttons let one button trigger another button column's action. Use the "Push button" action in the button editor to target a specific button column. A common use case: a canvas dashboard button that fires the "Mark Done" button action for every open task in the table.
// Canvas button: push the "Mark Done" button for all overdue tasks Tasks .Filter([Due Date] < Today() && [Status] != "Done") .ForEach(row, row.[Mark Done].Push())
ForEach(row, ModifyRow(row, ...)) is more explicit and easier to debug.
Values passed to ModifyRow() can be formula expressions, not just literals. This lets a single button behave differently based on the current state of the row.
ModifyRow( thisRow, [Status], If(thisRow.[Status] = "To Do", "In Progress", If(thisRow.[Status] = "In Progress", "Done", "To Do")) )
On each click: To Do → In Progress → Done → To Do → cycles continuously. No separate buttons per status.
If(thisRow.[Status] = "To Do", "▶ Start", If(thisRow.[Status] = "In Progress", "✓ Finish", "↺ Reopen"))
// Hide the "Mark Done" button when status is already Done thisRow.[Status] != "Done"
false for a row, the button disappears from that cell entirely — keeping the table clean and preventing accidental clicks on completed or locked rows.