Skip to main content

Columns

DSG is column based, meaning that all cells of a given column are of the same type and have the same widget. This is why it is more like Notion or Airtable, and less like Excel.

The columns array​

Columns are simple objects, and the list of columns is a simple array of column objects:

const columns = [{}, {}]

If you are using typescript:

import { Column } from 'react-datasheet-grid'

type Row = {
firstName: string
lastName: string
}

const columns: Column<Row>[] = [{}, {}]

Built-in columns​

To get you started, 6 simple columns are built-in:

  • textColumn
  • checkboxColumn
  • intColumn
  • floatColumn
  • dateColumn
  • isoDateColumn
  • percentColumn
textColumn
1
2
3
4
5
rows

Each built-in column handles rows of a very specific data type. For instance the textColumn expects all rows to be strings:

import {
DataSheetGrid,
textColumn,
} from 'react-datasheet-grid'

const ExampleStrings = () => {
const [ data, setData ] = useState(['foo', 'bar', 'baz'])

const columns = [textColumn]

return (
<DataSheetGrid
value={data}
onChange={setData}
columns={columns}
/>
)
}

And the checkboxColumn expects all rows to be booleans:

import {
DataSheetGrid,
checkboxColumn,
} from 'react-datasheet-grid'

const ExampleBooleans = () => {
const [ data, setData ] = useState([true, false, true])

const columns = [checkboxColumn]

return (
<DataSheetGrid
value={data}
onChange={setData}
columns={columns}
/>
)
}

This means that columns are very simple, we will see in the next sections how to integrate them in more complex scenarios.

Overriding column props​

Because columns are simple objects, you can easily override any property by spreading it. See the exhaustive list of properties a column has.

const columns = [
{
...textColumn,
title: 'Name',
minWidth: 200
}
]

This is a great way to factor common behaviors across multiple columns without repeating code.

Using objects as rows​

In a real world project rows often are objects, and we would like each column to handle a specific key of that object. This is where keyColumn comes in:

import {
DataSheetGrid,
checkboxColumn,
textColumn,
keyColumn,
} from 'react-datasheet-grid'

const Example = () => {
const [ data, setData ] = useState([
{ active: true, firstName: 'Elon', lastName: 'Musk' },
{ active: false, firstName: 'Jeff', lastName: 'Bezos' },
])

const columns = [
keyColumn('active', checkboxColumn),
keyColumn('firstName', textColumn),
keyColumn('lastName', textColumn),
]

return (
<DataSheetGrid
value={data}
onChange={setData}
columns={columns}
/>
)
}

keyColumn wraps all properties of a column and allows you to write simpler columns that don't need to worry about an entire row object. It also has a very positive performance impact.

Because columns wrapped with keyColumn are still regular objects, you can override any props by spreading it:

const columns = [
{
...keyColumn('active', checkboxColumn),
title: 'Active'
},
{
...keyColumn('firstName', textColumn),
title: 'First name'
},
{
...keyColumn('lastName', textColumn),
title: 'Last name'
},
]

Typescript​

keyColumn is a generic that takes the row type and the key as parameters:

const columns = [
{
...keyColumn<Row, 'active'>('active', checkboxColumn),
title: 'Active'
},
// ...
]

Unfortunately, due to the complexity of the type, you have to type the key twice: once for the generic type, and once for the parameter (eg. 'active' is written twice).

Responsive width​

Columns are responsive by design. DSG uses the flexbox algorithm to dynamically compute the width of each column.

By default, all columns have the same width and a min-width of 100:

{}
{}
{}

You can use the grow property to make a specific column grow faster. Here the middle column is twice as large as other columns:

{}
{
grow: 2
}
{}

You can pass grow: 0 to prevent a column from growing:

{}
{
grow: 0
}
{}

Use minWidth to prevent columns from shrinking too much. By default columns already have minWidth: 100:

{}
{
minWidth: 200
}
{}

Read more about each property in the API reference.

Building custom columns​

Built-in columns are there to get your project started, but often you end up building you own custom columns to fit your needs. Note that built-in columns and helpers have nothing special, they are built on top of this library and do not ofer any additional feature that would not be available otherwise.

Text-based columns​

To create a text-based column that simply has some custom parsing and formatting functions you do not have to implement a custom component from scratch and can instead use createTextColumn:

import { createTextColumn } from 'react-datasheet-grid'

const column = createTextColumn({ /* options */ })

// When using Typescript you may specify the data type:
const column = createTextColumn<number>({ /* options */ })

The createTextColumn function returns a column object that can be used normally:

const columns = [
{
...keyColumn(
'name',
createTextColumn({
placeholder: 'Name of the person',
alignRight: true,
//...
})
),
title: 'Name'
},
]

You can also create a custom re-usable column instead of inline it:

// columns/email.tsx
export const emailColumn = createTextColumn({ /* Custom parser & formatter for emails */ })

// index.tsx
import { emailColumn } from './columns/email'

const columns = [
{
...keyColumn('email', emailColumn),
title: 'Email'
},
]

placeholder​

Type: string
Default: null

alignRight​

Type: boolean
Default: false

continuousUpdates​

Type: boolean
Default: true

When true, data is updated as the user types, otherwise it is only updated on blur. Setting it to false will improve performance.

deletedValue​

Type: T
Default: null

Value to use when deleting the cell

parseUserInput​

Type: (value: string) => T

Parse what the user types

formatBlurredInput​

Type: (value: T) => string

Format the value of the input when it is blurred

formatInputOnFocus​

Type: (value: T) => string

Format the value of the input when it gets focused

formatForCopy​

Type: (value: T) => string

Format the value when copy

parsePastedValue​

Type: (value: string) => T

Parse the pasted value

Using a custom component​

If you need a more exotic column, you can write your own from scratch. A column consists of a custom component that renders the widget and a few props to control its behavior.

See a step-by-step example of how to implement a select column, or read the exhaustive list of properties a column has.

const columns = [
{
component: MyWidget,
title: 'My column'
}
]