ZYVOPMulti-Platform Sync
SeriesAI NewsWhy ZyVOPJoin Discord
LoginGet Started
ZYVOPMulti-Platform Sync

The Developer Publishing Hub. Write once, publish everywhere, and make your work citation-ready with built-in SEO, AEO, and GEO discovery support. Zero reader paywalls.

Content

  • Categories
  • Tags
  • Badges
  • Leaderboard
  • Write Article
  • Newsletter

Company

  • About Us
  • Why ZyVOP
  • Developer API & CLI
  • Write for Us
  • Contact

Connect

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • DMCA Policy
  • Code of Conduct

© 2026 ZyVOP. Developer Publishing Hub.

Zero paywalls · Full content ownership
All systems operational
HomeMantine List View Table - From Table to Finder

Mantine List View Table - From Table to Finder

Giovambattista Fazioli
Giovambattista Fazioli
Senior Full-stack Engineer, Lead DeveloperSupport
September 4, 2026
5 min read
Mantine List View Table - From Table to Finder
#react#TypeScript#webcomponents#ui

Row selection, keyboard navigation, context menus, column visibility, dual resize modes, and 6 exported hooks — one release, zero compromises.

Introduction

Picture the macOS Finder: you click a file, Shift+click to select a range, right-click for a context menu, double-click a column divider to auto-fit, and hide columns you don't need. Now picture doing all of that in a React table component — with full Mantine integration and zero external dependencies. That's what @gfazioli/mantine-list-view-table 2.0.0 delivers. This isn't an incremental update; it's a rewrite that transforms a sortable table into a complete Finder-style list view, with every piece of logic extracted into reusable, publicly exported hooks.

What's New

✨ Row Selection

Select rows exactly like macOS Finder. Single click selects one row, Cmd/Ctrl+Click toggles, Shift+Click selects a range. Both single and multiple modes are supported, with controlled and uncontrolled state.

<ListViewTablecolumns={columns}data={data}rowKey="id"selectionMode="multiple"onSelectionChange={(keys, records) => setSelected(keys)}selectedRowColor="blue"/>

Enter fullscreen mode Exit fullscreen mode

Selected rows get a visible highlight that desaturates when the component loses focus — matching Finder's behavior pixel for pixel.

⌨️ Keyboard Navigation

When selectionMode is set, keyboard navigation activates automatically:

Key

Action

Arrow Up/Down

Move focus between rows

Enter

Activate row (onRowActivate)

Space

Toggle selection

Home / End

Jump to first / last row

Cmd/Ctrl+A

Select all (multiple mode)

<ListViewTableselectionMode="multiple"enableKeyboardNavigationonRowActivate={(record) => openFile(record)}/>

Enter fullscreen mode Exit fullscreen mode

🖱️ Context Menu

Right-click any row to show a context menu powered by Mantine's Menu component. The clicked row is automatically selected before the menu appears. You get Mantine's full accessibility, keyboard support, and dark mode out of the box.

<ListViewTableselectionMode="single"renderContextMenu={({ record }) => (
    <>
      <Menu.Item leftSection={<IconCopy size={14} />}>Copy</Menu.Item>
      <Menu.Item leftSection={<IconDownload size={14} />}>Download</Menu.Item>
      <Menu.Divider />
      <Menu.Item color="red" leftSection={<IconTrash size={14} />}>Delete</Menu.Item>
    </>)}/>

Enter fullscreen mode Exit fullscreen mode

👁️ Column Visibility

Hide and show columns programmatically or let users toggle them by right-clicking the table header. Supports both controlled and uncontrolled modes.

<ListViewTablehiddenColumns={['size', 'modified']}onHiddenColumnsChange={setHiddenColumns}enableColumnVisibilityToggle/>

Enter fullscreen mode Exit fullscreen mode

↔️ Dual Resize Modes

The new resizeMode prop gives you two column resize behaviors:

  • standard (default) — width is traded between the dragged column and its right neighbor. Total table width stays fixed. Great for fixed-width layouts.

  • finder — only the dragged column changes width. The table grows freely, just like Finder. Pair with Table.ScrollContainer for horizontal scrolling.

<ListViewTable enableColumnResizing resizeMode="finder" />

Enter fullscreen mode Exit fullscreen mode

🎯 Double-Click Auto-Fit

Double-click any resize handle to auto-fit the column to its content — measured accurately using off-screen DOM clones. In standard mode, the adjacent column compensates to keep the total width constant.

🪝 6 Exported Hooks

Every piece of internal logic is now a standalone, reusable hook:

Hook

Purpose

useSorting

Sort state with controlled/uncontrolled modes

useColumnReorder

Drag-and-drop column reordering

useColumnResize

Column resize with standard/finder modes

useRowSelection

Row selection (single, multiple, range)

useKeyboardNavigation

Arrow/Enter/Space keyboard navigation

useColumnVisibility

Column show/hide management

Import them directly for advanced compositions:

import { useRowSelection, useKeyboardNavigation } from '@gfazioli/mantine-list-view-table';

Enter fullscreen mode Exit fullscreen mode

📋 New Props Summary

Prop

Type

Default

Description

selectionMode

`'single' \

'multiple'`

—

selectedRows

React.Key[]

—

Controlled selected row keys

defaultSelectedRows

React.Key[]

—

Default selected keys (uncontrolled)

onSelectionChange

(keys, records) => void

—

Selection change callback

selectedRowColor

MantineColor

—

Selected row background color

enableKeyboardNavigation

boolean

true when selectionMode is set

Enable keyboard nav

onRowActivate

(record, index) => void

—

Enter key callback

renderContextMenu

(info) => ReactNode

—

Context menu content (use Menu.Item)

onRowContextMenu

(record, index, event) => void

—

Right-click callback

hiddenColumns

string[]

—

Controlled hidden column keys

defaultHiddenColumns

string[]

—

Default hidden columns (uncontrolled)

onHiddenColumnsChange

(keys) => void

—

Hidden columns change callback

enableColumnVisibilityToggle

boolean

false

Right-click header to toggle columns

resizeMode

`'standard' \

'finder'`

'standard'

tableProps

Partial<TableProps>

—

Props passed to inner <Table>

stickyHeader

boolean

false

Sticky table header

stickyHeaderOffset

`number \

string`

0

tabularNums

boolean

false

Tabular number alignment

🎨 New Styles API

New selectors: selectedRow, focusedRow

New CSS variables:

Variable

Description

--list-view-selected-row-color

Background color of selected rows

--list-view-sticky-blur

Backdrop blur for sticky column overlay

💥 Breaking Changes

[!CAUTION]
This release contains breaking changes. Review the migration guide below before upgrading.

1. Props interface no longer extends TableProps

Table-level props (variant, layout, etc.) must now be passed through tableProps:

// Before<ListViewTable variant="vertical" />

// After<ListViewTable tableProps={{ variant: 'vertical' }} />

Enter fullscreen mode Exit fullscreen mode

2. enableColumnReordering and enableColumnResizing default to false

Previously both defaulted to true. Now you must opt in:

<ListViewTable enableColumnReordering enableColumnResizing />

Enter fullscreen mode Exit fullscreen mode

3. Component ref type changed

// Beforeconst ref = useRef<HTMLTableElement>(null);

// Afterconst ref = useRef<HTMLDivElement>(null);

Enter fullscreen mode Exit fullscreen mode

4. Context menu requires Menu.Item elements

The renderContextMenu prop must now return Mantine Menu.Item / Menu.Divider components instead of arbitrary JSX:

// BeforerenderContextMenu={() => (<Stack gap={0}>
    <UnstyledButton>Copy</UnstyledButton></Stack>)}

// AfterrenderContextMenu={() => (<>
    <Menu.Item leftSection={<IconCopy size={14} />}>Copy</Menu.Item></>)}

Enter fullscreen mode Exit fullscreen mode

5. visibleMediaQuery removed from column config

Use the new hiddenColumns prop instead for programmatic column visibility.

6. contextMenu Styles API selector removed

The context menu is now powered by Mantine's Menu, which has its own styling system.

🐛 Bug Fixes

  • Double-click no longer triggers drag resize — event.detail >= 2 guard prevents mousedown from starting a drag during double-click

  • Auto-fit preserves table width — adjacent column compensates the exact delta in standard mode

  • Controlled sort respects external data order — no internal re-sorting when sortStatus + onSort are both provided

  • Keyboard navigation bounds check — Enter/Space no longer fire with invalid indices after data filtering

  • Range selection clamped — Shift+click clamps to [0, data.length - 1] when data changes between clicks

🔧 Improvements

  • Resize handle UX overhaul — 14px hit area (20px touch), animated indicator line with spring curve

  • Finder-style header focus — inset bottom border instead of background highlight

  • Accessible focus indicator — :focus-visible outline on root element for keyboard users

  • Sticky columns without !important — cleaner CSS specificity

  • Vertical variant — now supports dot-notation keys (getNestedValue) and renderCell

Migration Guide

Step 1: Install the update

yarn add @gfazioli/mantine-list-view-table@^2.0.0

Enter fullscreen mode Exit fullscreen mode

Step 2: Wrap Table props in tableProps

If you passed Mantine Table props directly, move them:

// Before<ListViewTable variant="vertical" layout="fixed" />

// After<ListViewTable tableProps={{ variant: 'vertical', layout: 'fixed' }} />

Enter fullscreen mode Exit fullscreen mode

Step 3: Opt in to reordering/resizing

<ListViewTable enableColumnReordering enableColumnResizing />

Enter fullscreen mode Exit fullscreen mode

Step 4: Update ref type

const ref = useRef<HTMLDivElement>(null); // was HTMLTableElement

Enter fullscreen mode Exit fullscreen mode

Step 5: Update context menu

Replace custom JSX with Menu.Item from @mantine/core:

import { Menu } from '@mantine/core';

renderContextMenu={({ record }) => (<>
    <Menu.Item leftSection={<IconCopy size={14} />}>Copy</Menu.Item>
    <Menu.Divider />
    <Menu.Item color="red" leftSection={<IconTrash size={14} />}>Delete</Menu.Item></>)}

Enter fullscreen mode Exit fullscreen mode

Step 6: Replace visibleMediaQuery

// Before (on column){ key: 'size', visibleMediaQuery: '(min-width: 768px)' }

// After (on component)<ListViewTable hiddenColumns={isMobile ? ['size'] : []} />

Enter fullscreen mode Exit fullscreen mode

Compatibility

  • Mantine: 8.x

  • React: 18.x / 19.x

  • @tabler/icons-react: ^3.34.0

  • License: MIT

Links

  • 📦 npm

  • 📖 Documentation & Demos

  • 🔗 GitHub

  • 🎥 YouTube Tutorials

  • 🧩 Mantine Extensions Hub

Comments (0)

Login to post a comment.

Giovambattista Fazioli
Giovambattista Fazioli

Senior Full-stack Engineer, Lead Developer

Italian Senior Full-stack Engineer and Lead Developer on the Cloud team at Namecheap. I build developer tools, React/Mantine UI components and native macOS apps — mostly open source. I work across TypeScript, Next.js, Go and SwiftUI, and I've been coding since the Commodore/Assembly days. Creator of WP Bones and 25+ Mantine extensions, and maintainer of the Undolog open-source studio.

Support
Subscribe to Giovambattista Fazioli's Newsletter

More from Giovambattista Fazioli

View profile

FinderGit 0.29.0 — open a commit like a folder

There’s a moment, reading a commit list, where you want to know one small thing: which files did that one touch?

3 minSep 4

Netfox 0.18.0 — is it my connection, or the internet?

There is a question that comes up every time something feels slow, and until now Netfox could not...

3 minSep 4

Mantine Book — Grab Any Edge, Turn Any Page

A realistic iBooks-style book for React built on Mantine: stack two-sided pages and turn them by...

5 minSep 4

Netfox — The macOS app that never loses track of your network

I built Netfox because every existing answer to "what's actually on my network?" annoyed me. The...

5 minSep 4

Audio That Sees Itself

A Mantine-native audio player for React with waveform visualisation and a live spectrum analyser,...

5 minSep 4