To delete a data row from an Excel table with VBA, use the table’s ListRows collection: for example, tbl.ListRows(3).Delete removes the third data row. Set tbl to the relevant ListObject first; its row index counts table data rows, not worksheet row numbers.
How Excel table row deletion works
An Excel table, also called a ListObject in VBA, has a structured range with table-specific features such as filter buttons, column names, and calculated columns. A table’s ListRows collection contains its data rows. Calling Delete on one of those rows removes that record from the table and updates the table’s data range.
This is different from deleting a worksheet row with Rows(5).Delete or EntireRow.Delete. Those commands target worksheet rows, which can affect cells beyond the table. Use ListRows(index).Delete when your intention is to remove a record from a table. If other data sits beside or below the table, inspect the layout and test on a copy: worksheet-level deletion and table-row deletion are not interchangeable operations.
Table row indexes begin at 1 for the first data row, regardless of the row number where the table appears. The header and optional totals row are not members of ListRows. So ListRows(1) means the first record beneath the header, not worksheet row 1.
Delete a specific row by its table position
For a known table name and a known data-row position, this basic macro checks that the row exists before deleting it. Change the worksheet, table, and index to match your workbook.
Sub DeleteThirdTableRow()
Dim ws As Worksheet
Dim tbl As ListObject
' Identify the worksheet and table.
Set ws = ThisWorkbook.Worksheets("Sales")
Set tbl = ws.ListObjects("Table1")
' ListRows counts data rows only; do nothing if row 3 is absent.
If tbl.ListRows.Count >= 3 Then
tbl.ListRows(3).Delete
End If
End Sub
Run the macro from the Visual Basic Editor, or call it from another procedure. On Windows, open the editor with Alt+F11 or use Developer > Visual Basic. On a Mac, Option+F11 is commonly the editor shortcut, though some keyboards require Fn as well; the Developer tab is another route. Excel for the web can open a workbook containing VBA, but it cannot run or edit VBA macros.
Use the table’s actual name, which you can find by selecting a table cell and checking the Table Design tab’s Table Name box. Worksheet names and table names are separate: a worksheet called “Sales” may contain a table named “Table1.”
Delete the row containing the active cell
If a user selects any cell in a record and then runs a macro, calculate the selected cell’s position inside the table’s data body. The following example refuses to delete anything if the active cell is on another sheet, outside the table, or in an empty table.
Sub DeleteRowWithActiveCell()
Dim ws As Worksheet
Dim tbl As ListObject
Dim hit As Range
Dim rowIndex As Long
Set ws = ThisWorkbook.Worksheets("Sales")
Set tbl = ws.ListObjects("Table1")
' An empty table has no DataBodyRange to intersect.
If tbl.ListRows.Count = 0 Then Exit Sub
If Not (ActiveCell.Worksheet Is ws) Then Exit Sub
Set hit = Intersect(ActiveCell, tbl.DataBodyRange)
If hit Is Nothing Then
MsgBox "Select a cell in a table data row first."
Exit Sub
End If
' Convert the worksheet row to a ListRows index.
rowIndex = hit.Row - tbl.DataBodyRange.Row + 1
tbl.ListRows(rowIndex).Delete
End Sub
The macro removes the entire table record, not just the selected cell or column value. That is usually what “delete a row from a table” means. If you want to keep the record but clear one field, assign an empty value to the relevant cell instead of deleting the ListRow.
Delete rows that match a condition
For cleanup tasks, it is common to remove every record whose value in a named column meets a condition. Delete from the bottom of the table upward. After a deletion, rows below the deleted record move up in the table; a forward loop can therefore skip the next record as the indexes change.
Sub DeleteCancelledRows()
Dim ws As Worksheet
Dim tbl As ListObject
Dim i As Long
Dim statusValue As Variant
Set ws = ThisWorkbook.Worksheets("Sales")
Set tbl = ws.ListObjects("Table1")
' Avoid accessing DataBodyRange in an empty table.
If tbl.ListRows.Count = 0 Then Exit Sub
' Work upward so remaining row indexes do not shift past the loop.
For i = tbl.ListRows.Count To 1 Step -1
statusValue = tbl.ListColumns("Status").DataBodyRange.Cells(i, 1).Value
If Not IsError(statusValue) Then
If StrComp(CStr(statusValue), "Cancelled", vbTextCompare) = 0 Then
tbl.ListRows(i).Delete
End If
End If
Next i
End Sub
This version compares the Status value with “Cancelled” without distinguishing uppercase and lowercase letters. It skips cells containing Excel error values. The column name must match the table header; if the header is renamed, update the VBA reference. To delete only the first match, add an Exit For after the delete statement. For large tables, deleting many rows one by one may take time, so test performance with a representative copy of the data.
Find the correct table and column names
VBA needs the exact table name, and criteria-based code also needs the exact column header. A table’s name appears in Table Design when the table is selected. You can also list table names in the Immediate window by inspecting ws.ListObjects in the editor. Spaces in a column heading are allowed; refer to the complete heading as a string, such as tbl.ListColumns("Order Status").
When a workbook has several tables, avoid relying on whichever table happens to be selected. Explicitly qualify the worksheet and table as in the examples. ThisWorkbook means the workbook that contains the running VBA code; ActiveWorkbook means the workbook currently active in Excel. The distinction matters if a macro opens or switches between workbooks.
Common errors and edge cases
An “index out of range” error often means the macro requested a row number greater than ListRows.Count, or the table name is wrong. Check the count before deleting a known index. A “subscript out of range” error when setting the table can also result from a misspelled worksheet or table name.
- Empty table: It has no data rows, and
DataBodyRangeis Nothing. CheckListRows.Countbefore using the data body. - Header or totals row: These are not data rows. A
ListRowsindex cannot be used to target the header or totals row. - Filtered table: A filter hides records; it does not remove them. A loop through all
ListRowscan still examine hidden rows. Decide whether the macro should process all records or only visible ones. - Formulas and references: Removing a record changes the table’s rows. Table formulas and structured references generally adjust with the table, but check dependent formulas, charts, and downstream processes after running a deletion.
- External or refreshed data: If a table is loaded from a query or other source, a refresh may bring deleted records back or replace the table’s contents. Where possible, remove the record in the source or adjust the query rather than treating the loaded table as the permanent data store.
Another frequent mistake is assuming a table row index equals its worksheet row number. If the header is on worksheet row 8, the first data row is typically on row 9, but its VBA table index is still 1. Use the table’s ListRows index or calculate a position from DataBodyRange; do not pass a worksheet row number directly to ListRows.
Choose between deleting, clearing, and filtering
Delete a ListRow when the record should no longer belong to the table. Clear cell contents when the row must remain as a placeholder or preserve a fixed layout. Filter the table when the goal is only to hide records from view; filtering is reversible and does not erase data. If records need an audit trail, consider adding an “Archived” or “Inactive” status and filtering those rows out instead of permanently deleting them.
For a one-off manual removal, select a cell in the table row, right-click, and choose Delete > Table Rows. That menu action avoids writing code. VBA becomes useful when the same rule must be applied repeatedly, when a button should run the cleanup, or when multiple records must be processed consistently. A macro should express the intended scope clearly: table record, worksheet row, or cell contents.
Run macros safely
Save a copy of the workbook before running a deletion macro. VBA actions cannot be undone with Ctrl+Z, and an accidental deletion may not be recoverable from the current session. Save a workbook containing VBA in a macro-enabled format such as .xlsm; saving it as a standard .xlsx file does not retain VBA code.
Only enable macros from workbooks you trust. Before using a macro on important data, test it on a copy with a few representative records, confirm the table and column names, and check the results after it runs. For a recurring process, consider adding a confirmation prompt, a log of deleted records, or an archive step. Those safeguards are especially useful when the deletion rule is based on user-entered values that may contain spelling variations or unexpected errors.
Frequently Asked Questions
How do I delete a table row by its worksheet row number?
Convert the worksheet row to a table data-row index, or locate the row within DataBodyRange as in the active-cell example. Do not use the worksheet row number directly as a ListRows index.
Does ListRows(1).Delete delete the table header?
No. It deletes the first data row. The header and totals row are not included in the table’s ListRows collection.
Why does my loop skip some matching rows?
Deleting a row changes the indexes of the rows after it. Iterate from the last row to the first, as the condition-based example does, to avoid skipping records.
Can I delete a row from a filtered table?
Yes, but decide whether the macro should inspect all table records or only visible records. A normal loop over ListRows processes the collection, including records hidden by a filter.
Can I undo a VBA row deletion with Ctrl+Z?
No. Excel clears its normal undo history when VBA changes the workbook. Save a backup or copy before running a deletion macro.
Related
- Excel Not Responding: How Long Should You Wait?
- Excel Not Responding When Copying and Pasting: Fixes
- Excel Not Responding and Won’t Close? Try These Fixes
Try it: the Column Letter to Number: aA is 27, XFD is 16,384. Converts both ways.
More in VBA & macros
- VBA Code to Copy a Range in ExcelIn Excel VBA, copy a range by calling Range.Copy and naming the destination range. For example, sourceSheet.Range("A1:C10").Copy Destination:=targetSheet.Range("A1")…
- Excel VBA: Center a UserForm on Screen AutomaticallyTo center an Excel VBA UserForm on the screen, set its StartUpPosition property to 2 - CenterScreen before…
- Excel VBA: How to Save a Backup Copy of a WorkbookTo save a backup copy of the workbook that contains your VBA code, use ThisWorkbook.SaveCopyAs fullPath. For example,…
- Excel VBA Active Worksheet: How It Works and When to Use ItIn Excel VBA, ActiveSheet refers to the sheet currently selected in the active workbook. It is not a…
- Find a Z-Score in Excel VBA: A Simple Step-by-Step GuideTo find z-scores with Excel VBA, calculate the mean and standard deviation of your data, then use the…
- Active Range in VBA: What It Means and How to Use ItIn Excel VBA, “active range” usually means the cell or cells currently selected, but ActiveRange is not a…
Sources: Function behaviour and menu paths: Microsoft Support documentation for Excel. Method & sources
Spotted an error in this guide? Let us know.