Mantine List View Table

Undolog

@gfazioli/mantine-list-view-table

The Mantine component adds a Finder-style List View to the Mantine Table, allowing for column reordering and resizing.

Installation

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

After installation import package styles at the root of your application:

import '@gfazioli/mantine-list-view-table/styles.css';

You can import styles within a layer @layer mantine-list-view-table by importing @gfazioli/mantine-list-view-table/styles.layer.css file.

import '@gfazioli/mantine-list-view-table/styles.layer.css';

Usage

The ListViewTable component brings advanced table functionality inspired by the List View found in macOS Finder. Building on the core features of the Mantine Table component, it offers a familiar and intuitive interface for displaying lists of items in a structured, table-like format. Notably, it allows users to reorder columns and resize them dynamically, giving greater flexibility and control over data presentation. This makes it an excellent choice for applications that require a modern, customizable list view with enhanced interactivity.

File.txt12 KB
2024-06-01
Image.png2 MB
2024-06-02
Video.mp4125 MB
2024-06-03
Document.pdf500 KB
2024-06-04
Archive.zip1.5 GB
2024-06-05
Spreadsheet.xlsx300 KB
2024-06-06
Presentation.pptx2 MB
2024-06-07
Audio.mp35 MB
2024-06-08
Script.js15 KB
2024-06-09
Striped color
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { data } from './data';
import { columns } from './columns';


function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={data}
      rowKey="id"
      onRowClick={(row) => console.log('Clicked:', row.name)}
    />
  );
}

Column Width Constraints

You can control column widths using width, minWidth, and maxWidth properties. The component automatically adjusts initial widths to respect these constraints and prevents resizing beyond the specified limits.

Minimum Width

Use minWidth to ensure columns don't become too narrow. When the initial width is smaller than minWidth, the component automatically adjusts to the minimum value.

Documents
Folder
--2024-06-01
README.md
Markdown
2.1 KB2024-06-02
package.json
JSON
1.8 KB2024-06-03
src
Folder
--2024-06-04
image.png
PNG Image
45.2 KB2024-06-05
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={data}
      rowKey="id"
      withTableBorder
      withColumnBorders
      highlightOnHover
      enableColumnResizing
      onColumnResize={(columnKey, width) => {
        console.log(`Column '${columnKey}' resized to: ${width}px`);
      }}
    />
  );
}

Maximum Width

Use maxWidth to prevent columns from becoming too wide. When the initial width is larger than maxWidth, the component automatically adjusts to the maximum value.

Documents
Folder
--2024-06-01
README.md
Markdown
2.1 KB2024-06-02
package.json
JSON
1.8 KB2024-06-03
src
Folder
--2024-06-04
image.png
PNG Image
45.2 KB2024-06-05
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={data}
      rowKey="id"
      withTableBorder
      withColumnBorders
      highlightOnHover
      enableColumnResizing
      onColumnResize={(columnKey, width) => {
        console.log(`Column '${columnKey}' resized to: ${width}px`);
      }}
    />
  );
}

Both Minimum and Maximum Width

You can combine minWidth and maxWidth to create precise width constraints. The component will adjust initial widths to fit within these bounds and restrict resizing to the specified range.

Documents
Folder
--2024-06-01
README.md
Markdown
2.1 KB2024-06-02
package.json
JSON
1.8 KB2024-06-03
src
Folder
--2024-06-04
image.png
PNG Image
45.2 KB2024-06-05
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={data}
      rowKey="id"
      withTableBorder
      withColumnBorders
      highlightOnHover
      enableColumnResizing
      onColumnResize={(columnKey, width) => {
        console.log(`Column '${columnKey}' resized to: ${width}px`);
      }}
    />
  );
}

Column Width Behavior

The ListViewTable component provides flexible column width management that adapts to different scenarios. Understanding how width calculation works will help you create the optimal layout for your data.

Auto Width vs Fixed Width

When no width is specified for a column, it automatically adjusts to the content and available space. When a width is specified, the column maintains that exact width. You can mix both approaches within the same table.

Documents
Folder
--2024-06-01
README.md
Markdown
2.1 KB2024-06-02
package.json
JSON
1.8 KB2024-06-03
src
Folder
--2024-06-04
image.png
PNG Image
45.2 KB2024-06-05
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={data}
      rowKey="id"
      withTableBorder
      withColumnBorders
      highlightOnHover
      enableColumnReordering={false}
    />
  );
}

Mixed Width Scenarios

You can combine auto-width and fixed-width columns in the same table. This is particularly useful when you have some columns that need consistent sizing (like actions or status) and others that should adapt to content (like names or descriptions).

Documents
Folder
--2024-06-01
README.md
Markdown
2.1 KB2024-06-02
package.json
JSON
1.8 KB2024-06-03
src
Folder
--2024-06-04
image.png
PNG Image
45.2 KB2024-06-05
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={data}
      rowKey="id"
      withTableBorder
      withColumnBorders
      highlightOnHover
      enableColumnReordering={false}
    />
  );
}

Text Truncation with Ellipsis

When dealing with lengthy text content that exceeds the available column width, you can use the ellipsis and noWrap props to control how text overflow and wrapping are handled.

Ellipsis Property

Setting ellipsis: true on a column will truncate overflowing text with an ellipsis (...), providing a clean and consistent appearance. This is particularly useful for columns containing file names, descriptions, or other text that might vary significantly in length.

NoWrap Property

The noWrap property controls whether text can wrap to multiple lines within a cell:

  • noWrap: true - Prevents text from wrapping to multiple lines
  • noWrap: false (default) - Allows text to wrap naturally

Combining Ellipsis and NoWrap

You can combine these properties for different behaviors:

  • ellipsis: true + noWrap: true - Single line with ellipsis truncation (recommended)
  • ellipsis: true + noWrap: false - Multi-line text with ellipsis when needed
  • ellipsis: false + noWrap: true - Single line that may be cut off without ellipsis
  • ellipsis: false + noWrap: false - Default behavior with natural text wrapping

Both features work seamlessly with column resizing, allowing users to expand columns to see more content or shrink them to save space while maintaining appropriate text handling.

Very long document name that would normally overflow the column widthThis is a very long description that demonstrates how text can be truncated with ellipsis when the column is too narrow to fit all the content.Additional note for document 11234 Long Address Street, Some City, Some Country
README_with_extremely_long_filename_that_should_be_truncated.mdA comprehensive guide explaining all the features and functionality of this component library with detailed examples and use cases.Additional note for README5678 Another Long Address Avenue, Another City, Another Country
package.jsonConfiguration fileAdditional note for package.json91011 Short St, City, Country
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={data}
      rowKey="id"
      withTableBorder
      withColumnBorders
      highlightOnHover
      enableColumnResizing
      onColumnResize={(columnKey, width) => {
        console.log(`Column '${columnKey}' resized to: ${width}px`);
      }}
    />
  );
}

Text Truncation Presets

For consistent behavior across your application, you can use predefined text truncation configurations. This approach helps maintain consistency and makes it easier to apply appropriate truncation strategies based on content type.

Super long project name that demonstrates ellipsis truncation behavior in narrow columns

This is a comprehensive project description that contains multiple sentences and detailed information about the project scope, objectives, and expected outcomes. It demonstrates how multi-line ellipsis works.

In Progress with Additional Details

High Priority Item

2024-01-15

Mobile App Redesign

Complete overhaul of mobile application interface with focus on user experience improvements and accessibility features.

Completed

Medium

2024-02-20

API Documentation Update

Update technical documentation for REST API endpoints including examples and response schemas.

Review

Low

2024-03-10
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={data}
      rowKey="id"
      withTableBorder
      withColumnBorders
      highlightOnHover
      enableColumnResizing
    />
  );
}

Different Header and Cell Styling with cellStyle

While the ellipsis and noWrap properties apply the same styling to both table headers (TH) and data cells (TD), you can use the cellStyle property to create different behaviors between headers and cells. This gives you fine-grained control over how content is displayed in each part of the column.

Understanding the Behavior

The column-level properties (ellipsis, noWrap, textAlign, etc.) apply to both the header (TH) and the data cells (TD) in that column. However, the cellStyle property only affects the data cells (TD), allowing you to override the column-level styling specifically for the cell content while keeping different styling for the header.

Use Cases for Different Header/Cell Styling

  1. Header with ellipsis, cells with wrapping - Keep headers compact while allowing cell content to wrap naturally
  2. Header allows wrapping, cells use ellipsis - Show full header text but truncate long cell content
  3. Custom cell backgrounds or formatting - Apply visual enhancements only to data cells
  4. Dynamic cell styling - Apply different styles based on the data in each cell

Implementation Examples

The cellStyle property can be either a static style object or a function that receives the record and index, allowing for dynamic styling based on data:

Very long document name that would normally overflow the column width and require truncation with ellipsisThis is a very long description that demonstrates how text can be truncated with ellipsis when the column is too narrow to fit all the content. The header and cell can have different text wrapping behavior.
Folder
--2024-06-01
README_with_extremely_long_filename_that_should_be_truncated_differently_in_header_vs_cell.mdA comprehensive guide explaining all the features and functionality of this component library with detailed examples and use cases that span multiple lines.
Markdown Document
2.1 KB2024-06-02
package.jsonConfiguration file for project dependencies
JSON
1.8 KB2024-06-03
srcSource code directory containing all TypeScript files and components for the application
Folder
--2024-06-04
my_vacation_photos_from_summer_2024_trip_to_europe_including_italy_france_and_spain_with_beautiful_landscapes.pngHigh resolution image file containing memories from vacation with detailed metadata
PNG Image File
45.2 KB2024-06-05
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { data, columns } from './data';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={data}
      rowKey="id"
      withTableBorder
      withColumnBorders
      highlightOnHover
      enableColumnResizing
      onColumnResize={(columnKey, width) => {
        console.log(`Column '${columnKey}' resized to: ${width}px`);
      }}
    />
  );
}

Key Benefits

  • Flexibility: Different visual treatment for headers vs. data
  • User Experience: Headers can show full context while cells optimize for scanning
  • Dynamic Styling: Apply conditional formatting based on data values
  • Consistency: Maintain header layout while customizing cell presentation

This approach is particularly useful when building data-heavy interfaces where header clarity and cell readability have different requirements.

Horizontal Scrolling with Table.ScrollContainer

When your table content is wider than the available container width, you can use Mantine's Table.ScrollContainer component to enable smooth horizontal scrolling. This is especially useful for tables with many columns or when you need to maintain fixed column widths.

Basic Horizontal Scrolling

Wrap your ListViewTable with Table.ScrollContainer and set a minWidth to enable horizontal scrolling when the content exceeds the container width. All columns will scroll together horizontally.

Documents
Folder
--2024-06-01

Extra content 1

Extra content 2

Extra content 3

README.md
Markdown
2.1 KB2024-06-02

Extra content 1

Extra content 2

Extra content 3

package.json
JSON
1.8 KB2024-06-03

Extra content 1

Extra content 2

Extra content 3

src
Folder
--2024-06-04

Extra content 1

Extra content 2

Extra content 3

image.png
PNG Image
45.2 KB2024-06-05

Extra content 1

Extra content 2

Extra content 3

import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { Table } from '@mantine/core';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  return (
    <Table.ScrollContainer minWidth={1200}>
      <ListViewTable
        columns={columns}
        data={data}
        rowKey="id"
        withTableBorder
        withColumnBorders
        highlightOnHover
        enableColumnResizing={false}
      />
    </Table.ScrollContainer>
  );
}

Horizontal Scrolling with Sticky Columns

You can combine horizontal scrolling with sticky columns to keep important identifier columns (like names or IDs) visible while other columns scroll horizontally. Set sticky: true on the columns you want to remain fixed.

Documents
Folder
--2024-06-01

Extra content 1

Extra content 2

Extra content 3

README.md
Markdown
2.1 KB2024-06-02

Extra content 1

Extra content 2

Extra content 3

package.json
JSON
1.8 KB2024-06-03

Extra content 1

Extra content 2

Extra content 3

src
Folder
--2024-06-04

Extra content 1

Extra content 2

Extra content 3

image.png
PNG Image
45.2 KB2024-06-05

Extra content 1

Extra content 2

Extra content 3

import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { Table } from '@mantine/core';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  return (
    <Table.ScrollContainer minWidth={1200}>
      <ListViewTable
        columns={columns}
        data={data}
        rowKey="id"
        withTableBorder
        withColumnBorders
        highlightOnHover
        enableColumnResizing={false}
      />
    </Table.ScrollContainer>
  );
}

Scroll Area Integration

The ListViewTable works seamlessly with Mantine's ScrollArea component. This is useful when you want to create a fixed-height table with scrollable content while maintaining the table's sticky header functionality.

When used inside a ScrollArea, the stickyHeader prop will make the table header stick to the top of the scroll area, providing a consistent user experience during scrolling.

Documents
Folder
--2024-06-01
README.md
Markdown
2.1 KB2024-06-02
package.json
JSON
1.8 KB2024-06-03
src
Folder
--2024-06-04
image.png
PNG Image
45.2 KB2024-06-05
video.mp4
Video
12.5 MB2024-06-06
archive.zip
ZIP Archive
3.4 MB2024-06-07
Downloads
Folder
--2024-06-08
notes.txt
Text File
1.2 KB2024-06-09
node_modules
Folder
--2024-06-10
dist
Folder
--2024-06-11
LICENSE
Text
1.1 KB2024-06-12
.gitignore
Text
0.5 KB2024-06-13
tsconfig.json
JSON
2.3 KB2024-06-14
vite.config.ts
TypeScript
1.9 KB2024-06-15
eslint.config.js
JavaScript
0.8 KB2024-06-16
yarn.lock
Lock File
456.7 KB2024-06-17
pnpm-lock.yaml
Lock File
234.1 KB2024-06-18
rollup.config.js
JavaScript
3.2 KB2024-06-19
jest.config.js
JavaScript
1.4 KB2024-06-20
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { ScrollArea } from '@mantine/core';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  return (
    <ScrollArea h={250}>
      <ListViewTable
        columns={columns}
        data={data}
        rowKey="id"
        stickyHeader
        onRowClick={(record) => {
          console.log('Clicked:', record.name);
        }}
      />
    </ScrollArea>
  );
}

Styles API

ListViewTable supports Styles API, you can add styles to any inner element of the component with classNames prop. Follow Styles API documentation to learn more.

You can customize the appearance of the ListViewTable component using the Styles API. This allows you to modify styles for various parts of the component, such as the root, header cells, data cells, rows, and more.

File.txt12 KB
2024-06-01
Image.png2 MB
2024-06-02
Video.mp4125 MB
2024-06-03
Document.pdf500 KB
2024-06-04
Archive.zip1.5 GB
2024-06-05
Spreadsheet.xlsx300 KB
2024-06-06
Presentation.pptx2 MB
2024-06-07
Audio.mp35 MB
2024-06-08
Script.js15 KB
2024-06-09

Component Styles API

Hover over selectors to highlight corresponding elements

/*
 * Hover over selectors to apply outline styles
 *
 */

Advanced Features

The ListViewTable component provides internal implementations for sorting, column reordering, and column resizing by default. However, developers can take full control over these features when needed for custom business logic or integration with external state management.

External Sorting Control

By default, the component handles sorting internally when you click on sortable column headers. However, you can override this behavior to implement custom sorting logic, integrate with external APIs, or manage sorting state in your application's state management system.

When you provide both sortStatus and onSort props, the component will use external sorting mode. You'll need to handle the data sorting logic yourself and update the sortStatus when the user clicks on column headers.

Documents
Folder
--2024-06-01
README.md
Markdown
2.1 KB2024-06-02
image.png
PNG Image
45.2 KB2024-06-05
package.json
JSON
1.8 KB2024-06-03
src
Folder
--2024-06-04
import React from 'react';
import { ListViewTable, ListViewTableSortStatus } from '@gfazioli/mantine-list-view-table';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  const [sortStatus, setSortStatus] = React.useState<ListViewTableSortStatus>({
    columnKey: 'name',
    direction: 'asc',
  });

  const sortedData = React.useMemo(() => {
    const sorted = [...data].sort((a, b) => {
      const aValue = a[sortStatus.columnKey as keyof typeof a];
      const bValue = b[sortStatus.columnKey as keyof typeof b];

      if (sortStatus.direction === 'desc') {
        return String(bValue).localeCompare(String(aValue));
      }
      return String(aValue).localeCompare(String(bValue));
    });
    return sorted;
  }, [sortStatus]);

  return (
    <ListViewTable
      columns={columns}
      data={sortedData}
      rowKey="id"
      withTableBorder
      highlightOnHover
      sortStatus={sortStatus}
      onSort={setSortStatus}
    />
  );
}

External Column Reordering and Resizing

Similarly, column reordering and resizing are handled internally by default. You can override these behaviors by providing onColumnReorder and onColumnResize callbacks. This is useful when you need to persist column configurations, sync with external state, or implement custom reordering logic.

The component will still provide the visual feedback and drag-and-drop functionality, but you'll have full control over how the state changes are handled.

Documents
Folder
--2024-06-01
README.md
Markdown
2.1 KB2024-06-02
package.json
JSON
1.8 KB2024-06-03
src
Folder
--2024-06-04
image.png
PNG Image
45.2 KB2024-06-05
import React from 'react';
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { data, initialColumns } from './data';

function Demo() {
  const [currentColumns, setCurrentColumns] = React.useState(initialColumns);

  const handleColumnReorder = (fromIndex: number, toIndex: number) => {
    const newColumns = [...currentColumns];
    const [movedColumn] = newColumns.splice(fromIndex, 1);
    newColumns.splice(toIndex, 0, movedColumn);
    setCurrentColumns(newColumns);
    console.log('Column reordered from', fromIndex, 'to', toIndex);
  };

  const handleColumnResize = (columnKey: string, width: number) => {
    console.log('Column resized:', columnKey, 'to width:', width);
  };

  return (
    <ListViewTable
      columns={currentColumns}
      data={data}
      rowKey="id"
      withTableBorder
      highlightOnHover
      enableColumnReordering
      enableColumnResizing
      onColumnReorder={handleColumnReorder}
      onColumnResize={handleColumnResize}
      onRowClick={(record) => {
        console.log('Clicked:', record.name);
      }}
    />
  );
}

Sticky Header

The stickyHeader prop enables the table header to remain fixed at the top of the viewport (or scroll container) when the user scrolls through the table content. This is particularly useful for long tables where you want to keep the column headers visible at all times.

The sticky header feature works both with the document scroll and when the table is used inside a ScrollArea. When enabled, the header will maintain its position and remain accessible during scrolling, improving the user experience by providing constant context about the data structure.

You can also use the stickyHeaderOffset prop to adjust the sticky header position when your page has a fixed navigation bar or header. This ensures the table header doesn't overlap with other fixed elements on the page.

Documents
Folder
--2024-06-01
README.md
Markdown
2.1 KB2024-06-02
package.json
JSON
1.8 KB2024-06-03
src
Folder
--2024-06-04
image.png
PNG Image
45.2 KB2024-06-05
video.mp4
Video
12.5 MB2024-06-06
archive.zip
ZIP Archive
3.4 MB2024-06-07
Downloads
Folder
--2024-06-08
notes.txt
Text File
1.2 KB2024-06-09
node_modules
Folder
--2024-06-10
dist
Folder
--2024-06-11
LICENSE
Text
1.1 KB2024-06-12
.gitignore
Text
0.5 KB2024-06-13
tsconfig.json
JSON
2.3 KB2024-06-14
vite.config.ts
TypeScript
1.9 KB2024-06-15
eslint.config.js
JavaScript
0.8 KB2024-06-16
yarn.lock
Lock File
456.7 KB2024-06-17
pnpm-lock.yaml
Lock File
234.1 KB2024-06-18
rollup.config.js
JavaScript
3.2 KB2024-06-19
jest.config.js
JavaScript
1.4 KB2024-06-20
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={data}
      rowKey="id"
      withTableBorder
      withColumnBorders
      highlightOnHover
      stickyHeader
      stickyHeaderOffset={60}
      onRowClick={(record) => {
        console.log('Clicked:', record.name);
      }}
    />
  );
}

Table States

The ListViewTable component provides built-in support for common table states to enhance user experience during data loading and when no data is available.

Loading State

When data is being fetched or processed, you can show a loading indicator by setting the loading prop to true. This displays a spinner overlay while maintaining the table structure and headers.

import { ListViewTable } from '@gfazioli/mantine-list-view-table';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={[]}
      rowKey="id"
      height={400}
      withTableBorder
      loading
    />
  );
}

Custom Loading Props

You can customize the default Mantine Loader component by providing custom props through the loadingProps prop. This allows you to change the loader's size, color, and other properties without replacing the entire loading component.

import { ListViewTable } from '@gfazioli/mantine-list-view-table';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={[]}
      rowKey="id"
      height={400}
      withTableBorder
      loading
      loadingProps={{ size: 'xs', color: 'green', type: 'bars' }}
      // Note: loadingProps customizes the default Mantine Loader component
      // Available props: size, color, type, etc.
    />
  );
}

Custom Loading Component

For more advanced customization, you can provide a completely custom loading component using the loadingComponent prop. This prop accepts either a React element or a component function:

  • React Element: A pre-configured JSX element that will be rendered as-is
  • Component Function: A component that will receive loadingProps as props, allowing for dynamic customization

Loading files from server...

import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { RingProgress, Stack, Text } from '@mantine/core';

function Demo() {
  // Custom loading component as React element
  const customLoader = (
    <Stack align="center" gap="md">
      <RingProgress
        size={80}
        thickness={6}
        sections={[{ value: 100, color: 'grape' }]}
      />
      <Text size="sm" c="dimmed">
        Loading files from server...
      </Text>
    </Stack>
  );

  return (
    <ListViewTable
      columns={columns}
      data={[]}
      rowKey="id"
      height={400}
      withTableBorder
      loading
      loadingComponent={customLoader}
    />
  );
}

You can also pass a component function that will receive the loadingProps:

Synchronizing Data

This may take a few moments depending on your connection

import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { IconRefresh } from '@tabler/icons-react';
import { Button, Stack, Text, ThemeIcon, Title } from '@mantine/core';

// Custom loading component
const CustomLoadingScreen = ({ 
  title = 'Loading Files', 
  subtitle = 'Please wait while we fetch your data...',
  onRetry 
}: { 
  title?: string; 
  subtitle?: string; 
  onRetry?: () => void;
}) => (
  <Stack align="center" gap="lg" p="xl">
    <ThemeIcon size="xl" variant="light" color="blue">
      <IconRefresh size={24} />
    </ThemeIcon>
    <Stack align="center" gap="xs">
      <Title order={4}>{title}</Title>
      <Text size="sm" c="dimmed" ta="center">
        {subtitle}
      </Text>
    </Stack>
    {onRetry && (
      <Button variant="light" size="sm" onClick={onRetry}>
        Retry
      </Button>
    )}
  </Stack>
);

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={[]}
      rowKey="id"
      height={400}
      withTableBorder
      loading
      loadingComponent={CustomLoadingScreen}
      loadingProps={{
        title: 'Synchronizing Data',
        subtitle: 'This may take a few moments depending on your connection',
        onRetry: () => console.log('Retry clicked')
      }}
    />
  );
}

Empty State

When no data is available to display, you can customize the empty state using the emptyText prop. This prop accepts either a simple text string or a React component, giving you full flexibility to create rich, interactive empty states that provide better user experience and guidance.

Default Empty State

If you don't specify the emptyText prop, the table will show the default message: "No data available".

No data available

import { ListViewTable } from '@gfazioli/mantine-list-view-table';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={[]}
      rowKey="id"
      withTableBorder
      height={200}
      // emptyText prop is not specified, so it will use the default: "No data available"
    />
  );
}

Simple Text Empty State

You can provide a custom text message by passing a string to the emptyText prop:

No files found in this directory

import { ListViewTable } from '@gfazioli/mantine-list-view-table';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={[]}
      rowKey="id"
      withTableBorder
      height={200}
      emptyText="No files found in this directory"
    />
  );
}

Inline JSX Empty State

For slightly more visual appeal, you can pass inline JSX elements:

No documents available

import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { Group, Text, ThemeIcon } from '@mantine/core';
import { IconFolderOpen } from '@tabler/icons-react';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={[]}
      rowKey="id"
      withTableBorder
      height={200}
      emptyText={
        <Group gap="sm">
          <ThemeIcon size="sm" variant="light" color="blue">
            <IconFolderOpen size={14} />
          </ThemeIcon>
          <Text c="dimmed">No documents available</Text>
        </Group>
      }
    />
  );
}

Advanced Custom Component Empty State

For more sophisticated empty states, you can pass a React component that includes icons, custom styling, descriptions, and interactive elements like buttons:

No files found

Your folder is empty. Start by adding some files to see them here.

import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { IconFileX, IconFolderOpen, IconPlus } from '@tabler/icons-react';
import { Button, Group, Stack, Text, ThemeIcon } from '@mantine/core';

// Custom empty state component with icon and action buttons
const CustomEmptyState = () => (
  <Stack align="center" gap="md">
    <ThemeIcon size={64} variant="light" color="gray">
      <IconFileX size={32} />
    </ThemeIcon>
    <Stack align="center" gap="xs">
      <Text size="lg" fw={500} c="dimmed">
        No files found
      </Text>
      <Text size="sm" c="dimmed" ta="center">
        Your folder is empty. Start by adding some files to see them here.
      </Text>
    </Stack>
    <Group gap="sm">
      <Button leftSection={<IconPlus size={16} />} size="sm">
        Add File
      </Button>
      <Button variant="outline" leftSection={<IconFolderOpen size={16} />} size="sm">
        Browse Files
      </Button>
    </Group>
  </Stack>
);

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={[]}
      rowKey="id"
      withTableBorder
      height={300}
      emptyText={<CustomEmptyState />}
    />
  );
}

Vertical Variant

The ListViewTable component supports the variant="vertical" prop from Mantine Table component, which displays data in a key-value format where each row represents a property-value pair. This is particularly useful for displaying detailed information about a single item, such as configuration settings, user profiles, or metadata.

When using the vertical variant, consider setting layout="fixed" to ensure consistent column widths and a more structured appearance.

Epic name7.x migration
StatusOpen
Total issues135
Total story points874
Last updated atSeptember 26, 2024 17:41:26
import { ListViewTable } from '@gfazioli/mantine-list-view-table';
import { data } from './data';
import { columns } from './columns';

function Demo() {
  return (
    <ListViewTable
      columns={columns}
      data={data}
      rowKey={(row, i) => row.label + i}
      withTableBorder
      variant="vertical"
      layout="fixed"
    />
  );
}