Filtering a CSV column by its actual values is one of those operations that should take three seconds and frequently takes thirty: open the file in a spreadsheet, wait for it to load, click into the header, find the dropdown, scroll a list of 12,000 unique strings to find the four you care about. csvdiff.app already had a per-column value filter; this update makes it dramatically faster to use on real-world data — including columns full of empties, datetime strings, and values you want to clean up in bulk.
Every change in this post happens in your browser. Your CSV bytes never leave the tab. The features below work on any CSV opened in either the diff view or the standalone viewer.
Filter by Exact Value, Including Empty Cells
Click the funnel icon in any column header and you get a popover listing every distinct value in that column, sorted by frequency, with the row count next to each. Tick a value (or several) and the table filters down to rows where that column matches. Untick to clear, or hit the Clear shortcut in the popover header.
A long-standing miss in the previous version: empty cells were silently excluded from the value list. If your "department" column has 15 rows with a value and 4 rows that are blank, you could filter to the 15 — but had no way to surface the 4 blanks except by scrolling the table looking for dashes. The filter now includes blank values as a dedicated entry (rendered as italic "empty" with the count), pushed to the bottom of the list. Selecting it filters to rows where that column is blank — useful for finding missing data, validating exports, or zeroing in on rows that need follow-up.
Search Inside the Filter — Format-Aware
When a column has hundreds of unique values, scanning a list is too slow. The filter popover has a search box that narrows the value list as you type. New in this update: search matches both the raw value and the formatted display value. If you have applied a Currency format to a salary column, searching "120,000" finds the row whose underlying value is "1.2e5" — the search sees what your eyes see. Same for dates: searching "Mar 14" matches an underlying ISO string of 2022-03-14.
Datetime Format Support — 2020-07-31 14:32:09.000
A frequent shape in database exports is a SQL-style datetime: 2020-07-31 14:32:09.000. Earlier, the column format menu auto-detected a Date but only offered date-only outputs (YYYY-MM-DD, MMM DD YYYY, and so on), which threw away the time component. The Date format now exposes datetime outputs that preserve the time:
- –YYYY-MM-DD HH:mm:ss — full ISO-style datetime
- –YYYY-MM-DD HH:mm — minute precision, no seconds
- –MM/DD/YYYY HH:mm — US-style with time
- –DD MMM YYYY HH:mm — readable mixed format
Auto-detection got smarter too: if half or more of the date-shaped samples carry a time component, the default output flips to YYYY-MM-DD HH:mm:ss instead of YYYY-MM-DD. The parser also normalizes "YYYY-MM-DD HH:mm:ss[.fff]" to ISO internally so Safari (which is stricter than Chrome about non-ISO strings) parses these dates reliably.
Copy Unique Column Values to Clipboard
Common analyst chore: "give me the list of distinct order statuses in this export". A new copy button in the filter popover header does it in one click. With nothing selected, it copies every value visible in the list (after any search filter you have applied). With one or more values ticked, it copies just the selection. The copied text uses the formatted display values, newline-separated — so pasting into a doc, a Slack message, or a spreadsheet column gives you exactly what you saw on screen.
pending shipped delivered returned cancelled
Tip: combine it with the search box. Type "201" in the search to narrow a 50,000-row "order_id" column to only IDs containing 201, then copy the filtered list directly. No spreadsheet round-trip.
Bulk Find-and-Replace, With a Row Flash
Selecting one or more values in the filter popover opens a small replace bar at the top. Type a replacement, hit Apply, and every cell in the column whose value matches your selection is rewritten. This was already there — what is new is the surrounding UX:
- –Affected rows briefly flash green to show exactly which rows were touched — instead of the whole table silently re-rendering and leaving you to guess.
- –The filter no longer clears after Apply. It re-pins to the new replacement value, so the same set of rows stays in view. You can verify the change, then clear the filter when you are ready.
- –Replace previews show the formatted display values, so a date or number column shows real-looking strings in the preview block before you commit.
| # | department |
|---|---|
| 1 | eng→engineer |
| 2 | eng→engineer |
| 3 | eng→engineer |
| 4 | eng→engineer |
| 5 | eng→engineer |
Higher-Contrast Count Pills
Small visual change worth calling out: the row-count pill next to each value in the filter list used to be tertiary-text color on the lightest fill, which was hard to read on bright displays. It now uses secondary-text on a slightly stronger fill — readable at a glance, still subdued enough not to compete with the value name itself.
Why the Filter Stays Pinned After Replace
The previous behavior was to clear the filter after Apply. The intent was "you replaced those values, so they no longer exist; clearing the filter avoids showing zero rows." In practice it meant the table reset to all rows and you lost track of what just happened. The new behavior — re-pinning the filter to the replacement value — keeps continuity: the same rows that were filtered before remain filtered after, the flash animation shows you which ones changed, and one click on Clear puts you back to seeing the whole table when you are done. It is a smaller change than the rest, but it is the one that makes the workflow feel coherent.
Try It
Open any CSV in the viewer or the diff tool, hover a column header, and click the funnel icon. Search, filter, copy, replace — all in one popover, all on your machine. If you have not used csvdiff.app before, drop two files into the diff page or one file into the viewer and start there.