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'
}
]