react-grind

v1.0.14

Getting Started

Introduction

React Grid is a tabular View library used within the Tenqube company.
It is composed of React components and can be implemented easily and intuitively by passing the data constituting the table as Props.

It is still an early version, so there may be unstable parts. Please register the problematic part as an issue on GitHub.

Installation

Terminal
npm install @tenqube/react-grid

Features

Change and remember column width

You can change the size of each column in the table by enabling the scalable setting in options, and the changes will be saved and persisted in web storage.

Fixed column not working to scroll

If you enter a size in the fixedSize setting in options, the column is fixed by that size. (default 0)

Other basic features..

Provided as a sorting status callback by column.

Specifying per-row classes for styling.

Provides column types such as checkbox and toggle.

Browser compatibility

Chrome
IE
Edge
Safari
Firefox

Quick Start

React Grid makes it simple to construct a table view by passing the promised columns and rows as Props.
and below is a simple configuration example.

Simple Code

GridComponent.tsx
import React from 'react'
import Grid, { GridType, IPropsColumn, RowType } from '@tenqube/react-grid'

const GridComponent = () => {

  const columns: Array<IPropsColumn> = [{
    id: 'week',
    name: 'THIS WEEK',
    type: GridType.String
  }, {
    id: 'title',
    name: 'TITLE',
    type: GridType.String
  }, {
    id: 'artist',
    name: 'ARTIST',
    type: GridType.String,
  }, {
    id: 'award',
    name: 'AWARD',
    type: GridType.String
  }]

  const rows: Array<Array<RowType>> = [[
    '1', 'Last Night', 'Morgan Wallen', '★'
  ], [
    '2', 'Flowers', 'Miley Cyrus', ''
  ], [
    '3', 'Kill Bill', 'SZA', ''
  ], [
    '4', 'Calm Down', 'Rema & Selena Gomez', '★'
  ], [
    '5', 'Favorite Song', 'Toosii', '★'
  ]]

  return (
    <Grid id={'billboard'} columns={columns} rows={rows} />
  )

}

export default GridComponent

Previews

THIS WEEK
TITLE
ARTIST
AWARD

1

Last Night

Morgan Wallen

2

Flowers

Miley Cyrus

3

Kill Bill

SZA

4

Calm Down

Rema & Selena Gomez

5

Favorite Song

Toosii

Props

React Grid provides props of id, columns, rows, options and addClassNameByRows.

ID

The id props use a unique value for each table element as a delimiter. Currently, this value is used as a separator to remember the column width value when using the scalable option.

If you don't use the scalable option, it doesn't matter too much if the value isn't unique, but it can affect future features.
A unique value is recommended.

Type
Required

String

Columns, Rows

Column configuration is performed according to the data type of the corresponding column. Column type is provided as Enum under the name of GridType in the library.

Hidden

Hidden types can add data that can be used internally without being displayed on the screen.

Property
Type
Required

id

string

type

Enum(GridType.Hidden) | number(0)

The data type for rows is string.

HiddenTypeComponent.tsx
import React from 'react'
import Grid, { GridType, IPropsColumn, RowType } from '@tenqube/react-grid'

const HiddenTypeComponent = () => {

  const columns: Array<IPropsColumn> = [{
    id: 'hidden',
    type: GridType.Hidden
  }]

  const rows: Array<Array<RowType>> = [[
    'data1'
  ], [
    'data2'
  ]]

  return (
    <Grid id={'hidden'} columns={columns} rows={rows} />
  )

}

export default HiddenTypeComponent

The rows type of Hidden is string.
The table is not printed in the above code because Hidden values are not printed.

Checkbox

Property
Type
Required

id

string

type

Enum(GridType.Checkbox) | number(1)

callback

(isAll: boolean, rowIdx: number, columnIdx: number): void

width

number

className

string

CheckboxTypeComponent.tsx
import React, { useState } from 'react'
import Grid, { GridType, IPropsColumn, RowType } from '@tenqube/react-grid'

const CheckboxTypeComponent = () => {

  const [rows, setRows] = useState<Array<Array<RowType>>>([[true], [false]])

  const handleClickCheckbox = (isAll: boolean, rowIdx: number, columnIdx: number) => {
    if(isAll) {
      const newRows = rows.map((row) => {
        const cloneRow = [...row]
        cloneRow[0] = !rows.every((row) => row[0] === true)
        return cloneRow
      })
      setRows(newRows)
    } else {
      const cloneRows = rows.map(row => [...row])
      cloneRows[rowIdx][columnIdx] = !cloneRows[rowIdx][columnIdx]
      setRows(cloneRows)
    }
  }

  const columns: Array<IPropsColumn> = [{
    id: 'checkbox',
    type: GridType.Checkbox,
    callback: handleClickCheckbox
  }]

  return (
    <Grid id={'checkbox'} columns={columns} rows={rows} />
  )

}

export default CheckboxTypeComponent

The callback function provides three arguments, isAll, rowIdx, and columnIdx.
A value of isAll means the difference between checking the head checkbox and checking the body checkbox. Based on the above factors, freely compose and use a callback function.

Previews

String

enum
enum OrderType {
  Default,
  ASC,
  DESC
}
Property
Type
Required

id

string

type

Enum(GridType.String) | number(2)

name

string

width

number

className

string

isSorting

boolean

callback

(columnId: string, orderType: OrderType) => void

StringTypeComponent.tsx
import React, { useState } from 'react'
import Grid, { GridType, IPropsColumn, RowType } from '@tenqube/react-grid'

const StringTypeComponent = () => {

  const ascRows = [['aaa'], ['bbb'], ['ccc']]
  const descRows = [['ccc'], ['bbb'], ['aaa']]

  const [rows, setRows] = useState<Array<Array<RowType>>>(ascRows)

  const handleSorting = (columnId: string, orderType: OrderType) => {
    setRows(orderType === OrderType.ASC ? ascRows : descRows)
  }

  const columns: Array<IPropsColumn> = [{
    id: 'string',
    name: 'Text',
    type: GridType.String,
    isSorting: true,
    callback: handleSorting
  }]

  return (
    <Grid id={'string'} columns={columns} rows={rows} />
  )

}

export default StringTypeComponent

The callback property of string type has meaning only when isSorting property is true.
The callback function is called when the sort icon is selected and provides the columnId and orderType arguments.

Previews

Text

aaa

bbb

ccc

Toggle

Property
Type
Required

id

string

type

Enum(GridType.Toggle) | number(3)

callback

(rowIdx: number, columnIdx: number) => void

name

string

width

number

className

string

ToggleTypeComponent.tsx
import React, { useState } from 'react'
import Grid, { GridType, IPropsColumn, RowType } from '@tenqube/react-grid'

const ToggleTypeComponent = () => {

  const [rows, setRows] = useState<Array<Array<RowType>>>([[true], [false]])

  const handleToggle = (rowIdx: number, columnIdx: number) => {
    const cloneRows = rows.map(row => [...row])
    cloneRows[rowIdx][columnIdx] = !cloneRows[rowIdx][columnIdx]
    setRows(cloneRows)
  }

  const columns: Array<IPropsColumn> = [{
    id: 'toggle',
    name: 'Toggle',
    type: GridType.Toggle,
    callback: handleToggle
  }]

  return (
    <Grid id={'toggle'} columns={columns} rows={rows} />
  )

}

export default ToggleTypeComponent

Previews

Toggle

Image

Property
Type
Required

id

string

type

Enum(GridType.Image) | number(4)

name

string

width

number

className

string

ImageTypeComponent.tsx
import React from 'react'
import Grid, { GridType, IPropsColumn, RowType } from '@tenqube/react-grid'

const ImageTypeComponent = () => {

  const columns: Array<IPropsColumn> = [{
    id: 'image',
    name: 'Image',
    type: GridType.Image
  }]

  const rows: Array<Array<RowType>> = [[
    'https://tenqube-images.s3.ap-northeast-2.amazonaws.com/labs/imagetype-example.png'
  ]]

  return (
    <Grid id={'image'} columns={columns} rows={rows} />
  )

}

export default ImageTypeComponent

The image type column data is in the form of a string, and the image is displayed using the URI Path.

Previews

Image

Button

Property
Type
Required

id

string

type

Enum(GridType.Button) | number(6)

callback

(rowIdx: number, columnIdx: number) => void

name

string

width

number

className

string

ButtonTypeComponent.tsx
import React from 'react'
import Grid, { GridType, IPropsColumn, RowType } from '@tenqube/react-grid'

const ButtonTypeComponent = () => {

  const handleClickButton = (rowIdx: number, columnIdx: number) => {
    window.alert(`rowIdx: ${rowIdx}, columnIdx: ${columnIdx}`)
  }

  const columns: Array<IPropsColumn> = [{
    id: 'button',
    name: 'Button',
    type: GridType.Button,
    callback: handleClickButton
  }]

  const rows: Array<Array<RowType>> = [[
    'button'
  ]]

  return (
    <Grid id={'button'} columns={columns} rows={rows} />
  )

}

export default ButtonTypeComponent

Button type requires callback attribute. This callback is called when a button is selected and provides the rowIdx(row index) and columnIdx(column index) values of the selected button as arguments.

Previews

Button

Items

Property
Type
Required

id

string

type

Enum(GridType.Items) | number(7)

items

Array<FC<{ rowIdx: number; columnIdx: number }> | ReactNode>

name

string

width

number

className

string

isSorting

boolean

callback

(columnId: string, orderType: OrderType) => void

ItemsTypeComponent.tsx
import React from 'react'
import Grid, { GridType, IPropsColumn, RowType } from '@tenqube/react-grid'

const ItemComponent = ({ text }) => {
  return (
    <p style={{
      lineHeight: '24px',
      padding: '10px 15px'
    }}>
      { text }
    </p>
  )
}

const ItemsTypeComponent = () => {

  const columns: Array<IPropsColumn> = [{
    id: 'items',
    name: 'Items',
    type: GridType.Items,
    items: [
      <ItemComponent text={'ReactNode Type.'} />,
      ({ rowIdx, columnIdx }) => {
        const text = `FC Type. (rowIdx: ${rowIdx}, columnIdx: ${columnIdx})`
        return (
          <ItemComponent text={text} />
        )
      }
    ]
  }]

  const rows: Array<Array<RowType>> = [[
    0
  ], [
    1
  ]]

  return (
    <Grid id={'items'} columns={columns} rows={rows} />
  )

}

export default ItemsTypeComponent

The Items type declares component-type array data in columns, and rows data is declared as the index value of the array. If the item component requires a rowIdx(row index) and columnIdx(column index), it can be configured as a functional component using the provided arguments.
Although not included in the sample code, the sorting function can be implemented through the isSorting property and callback function, just like the String type.

Previews

Items

ReactNode Type.

FC Type. (rowIdx: 1, columnIdx: 0)

Input(text)

Property
Type
Required

id

string

type

Enum(GridType.InputText) | number(8)

callback

(rowIdx: number, columnIdx: number, value: string) => void

name

string

width

number

className

string

InputTextTypeComponent.tsx
import React, { useState } from 'react'
import Grid, { GridType, IPropsColumn, RowType } from '@tenqube/react-grid'

const InputTextTypeComponent = () => {

  const [rows, setRows] = useState<Array<Array<RowType>>>([['aaa'], ['bbb']])

  const handleChange = (rowIdx: number, columnIdx: number, value: string) => {
    const cloneRows = rows.map(row => [...row])
    cloneRows[rowIdx][columnIdx] = value
    setRows(cloneRows)
  }

  const columns: Array<IPropsColumn> = [{
    id: 'input-text',
    name: 'Input Text',
    type: GridType.InputText,
    callback: handleChange
  }]

  return (
    <Grid id={'input-text'} columns={columns} rows={rows} />
  )

}

export default InputTextTypeComponent

The Input(text) type is an HTML input tag whose value can be modified by the user. Modification information can be checked through the callback function.

Previews

Input Text

Input(number)

Property
Type
Required

id

string

type

Enum(GridType.InputNumber) | number(9)

callback

(rowIdx: number, columnIdx: number, value: number) => void

name

string

width

number

className

string

InputNumberTypeComponent.tsx
import React, { useState } from 'react'
import Grid, { GridType, IPropsColumn, RowType } from '@tenqube/react-grid'

const InputNumberTypeComponent = () => {

  const [rows, setRows] = useState<Array<Array<RowType>>>([[1], [2]])

  const handleChange = (rowIdx: number, columnIdx: number, value: number) => {
    const cloneRows = rows.map(row => [...row])
    cloneRows[rowIdx][columnIdx] = value
    setRows(cloneRows)
  }

  const columns: Array<IPropsColumn> = [{
    id: 'input-nunber',
    name: 'Input Number',
    type: GridType.InputNumber,
    callback: handleChange
  }]

  return (
    <Grid id={'input-number'} columns={columns} rows={rows} />
  )

}

export default InputNumberTypeComponent

Same as Input(text) type. However, the input's data type is number.

Previews

Input Number

Array

Property
Type
Required

id

string

type

Enum(GridType.Array) | number(10)

name

string

width

number

className

string

ArrayTypeComponent.tsx
import React from 'react'
import Grid, { GridType, IPropsColumn, RowType } from '@tenqube/react-grid'

const ArrayTypeComponent = () => {

  const columns: Array<IPropsColumn> = [{
    id: 'array',
    name: 'Array',
    type: GridType.Array
  }]

  const rows: Array<Array<RowType>> = [[
    ['aaa', 'bbb', 'ccc']
  ]]

  return (
    <Grid id={'array'} columns={columns} rows={rows} />
  )

}

export default ArrayTypeComponent

The array type receives data in the form of an array in rows and outputs them by creating small boxes in columns.

Previews

Array
aaabbbccc

Component

Property
Type
Required

id

string

type

Enum(GridType.Component) | number(11)

name

string

width

number

className

string

isSorting

boolean

callback

(columnId: string, orderType: OrderType) => void

ComponentComponent.tsx
import React from 'react'
import Grid, { GridType, IPropsColumn, RowType } from '@tenqube/react-grid'

const ComponentTypeComponent = () => {

  const columns: Array<IPropsColumn> = [{
    id: 'component',
    name: 'Component',
    type: GridType.Component
  }]

  const rows: Array<Array<RowType>> = [[
    items: [
      <ItemComponent text={'ReactNode Type.'} />,
      ({ rowIdx, columnIdx }) => {
        const text = `FC Type. (rowIdx: ${rowIdx}, columnIdx: ${columnIdx})`
        return (
          <ItemComponent text={text} />
        )
      }
    ]
  ]]

  return (
    <Grid id={'component'} columns={columns} rows={rows} />
  )

}

export default ComponentTypeComponent

Although not included in the sample code, the sorting function can be implemented through the isSorting property and callback function, just like the String type.

Previews

Component

ReactNode Type.

FC Type. (rowIdx: 1, columnIdx: 0)

Options

Provides a scalable property that can change the size of a column and a fixedSize property that can specify the number of columns that do not operate on scrolling.

Property
Type
Default

scalable

boolean | IPropsScalableOption

false

fixedSize

number

0

scroll

IPropsScrollOption

null

Scalable

You can change the size of a table column by activating the scalable option. And the changed size is saved and maintained in web storage.

Saving to session storage is the default option when the scalable option is enabled.

IPropsScalableOption

Property
Type
Default
Required

enable

boolean

false

storage

boolean | IPropsStorageOption

true

IPropsStorageOption

Property
Type
Default
Required

enable

boolean

true

target

'local' | 'session'

'session'

In IPropsStorageOption, target value means WebStorage.

ScalableComponent.tsx
import React from 'react'
import Grid, { GridType, IPropsColumn, RowType, IPropsOptions } from '@tenqube/react-grid'

const ScalableComponent = () => {

  const columns: Array<IPropsColumn> = [{
    id: 'week',
    name: 'THIS WEEK',
    type: GridType.String
  }, {
    id: 'title',
    name: 'TITLE',
    type: GridType.String
  }, {
    id: 'artist',
    name: 'ARTIST',
    type: GridType.String,
  }, {
    id: 'award',
    name: 'AWARD',
    type: GridType.String
  }, {
    id: 'last-week',
    name: 'LAST WEEK',
    type: GridType.String
  }, {
    id: 'peak-pos',
    name: 'PEAK POS.',
    type: GridType.String
  }]

  const rows: Array<Array<RowType>> = [[
    '1', 'Last Night', 'Morgan Wallen', '★', '1', '1'
  ], [
    '2', 'Flowers', 'Miley Cyrus', '', '3', '1'
  ]]

  const options: IPropsOptions = {
    scalable: true
  }

  return (
    <Grid id={'billboard-scalable'} columns={columns} rows={rows} options={options} />
  )

}

export default ScalableComponent

In its most basic form, if the scalable value is set to true, the changed column size is stored in session storage and maintained until the tab is closed.

Previews

THIS WEEK
TITLE
ARTIST
AWARD
LAST WEEK
PEAK POS.

1

Last Night

Morgan Wallen

1

1

2

Flowers

Miley Cyrus

3

1

ScalableComponent.tsx
...
const options: IPropsOptions = {
  scalable: {
    enable: true,
    storage: false
  }
}
...

If the storage value is set to false while the scalable value is enabled, the size of the column will not be maintained when refreshing.

Previews

THIS WEEK
TITLE
ARTIST
AWARD
LAST WEEK
PEAK POS.

1

Last Night

Morgan Wallen

1

1

2

Flowers

Miley Cyrus

3

1

FixedSize

Columns are fixed from the left by the value of the fixedSize option.

FixedSizeOneComponent.tsx
import React from 'react'
import Grid, { GridType, IPropsColumn, RowType, IPropsOptions } from '@tenqube/react-grid'

const FixedSizeOneComponent = () => {

  const columns: Array<IPropsColumn> = [{
    id: 'week',
    name: 'THIS WEEK',
    type: GridType.String
  }, {
    id: 'title',
    name: 'TITLE',
    type: GridType.String
  }, {
    id: 'artist',
    name: 'ARTIST',
    type: GridType.String,
  }, {
    id: 'award',
    name: 'AWARD',
    type: GridType.String
  }, {
    id: 'last-week',
    name: 'LAST WEEK',
    type: GridType.String
  }, {
    id: 'peak-pos',
    name: 'PEAK POS.',
    type: GridType.String
  }]

  const rows: Array<Array<RowType>> = [[
    '1', 'Last Night', 'Morgan Wallen', '★', '1', '1'
  ], [
    '2', 'Flowers', 'Miley Cyrus', '', '3', '1'
  ]]

  const options: IPropsOptions = {
    fixedSize: 1
  }

  return (
    <Grid id={'billboard-fixed-1'} columns={columns} rows={rows} options={options} />
  )

}

export default FixedSizeOneComponent

Previews

THIS WEEK
TITLE
ARTIST
AWARD
LAST WEEK
PEAK POS.

1

Last Night

Morgan Wallen

1

1

2

Flowers

Miley Cyrus

3

1

If the number of fixed columns is set to two, it is as follows.

FixedSizeTwoComponent.tsx
const options: IPropsOptions = {
  fixedSize: 2
}

Previews

THIS WEEK
TITLE
ARTIST
AWARD
LAST WEEK
PEAK POS.

1

Last Night

Morgan Wallen

1

1

2

Flowers

Miley Cyrus

3

1

Scroll

The scroll options let you decide whether scrolling is controlled internally or externally.

IPropsScrollOption

Property
Type
Default
Required

enable

boolean

false

type

'inner' | 'outer'

inner

height

number

0

If you specify the inner type of the option and the height value, an inner scroll is created.

ScrollInnerComponent.tsx
import React from 'react'
import Grid, { GridType, IPropsColumn, RowType, IPropsOptions } from '@tenqube/react-grid'

const ScrollInnerComponent = () => {

  const columns: Array<IPropsColumn> = [{
    id: 'week',
    name: 'THIS WEEK',
    type: GridType.String
  }, {
    id: 'title',
    name: 'TITLE',
    type: GridType.String
  }, {
    id: 'artist',
    name: 'ARTIST',
    type: GridType.String,
  }, {
    id: 'award',
    name: 'AWARD',
    type: GridType.String
  }, {
    id: 'last-week',
    name: 'LAST WEEK',
    type: GridType.String
  }, {
    id: 'peak-pos',
    name: 'PEAK POS.',
    type: GridType.String
  }]

  const rows: Array<Array<RowType>> = [[
    '1', 'Last Night', 'Morgan Wallen', '★', '1', '1'
  ], [
    '2', 'Flowers', 'Miley Cyrus', '', '3', '1'
  ], [
    '3', 'Kill Bill', 'SZA', '', '', ''
  ], [
    '4', 'Calm Down', 'Rema & Selena Gomez', '★', '', ''
  ], [
    '5', 'Favorite Song', 'Toosii', '★', '', ''
  ]]

  const options: IPropsOptions = {
    scroll: {
      enable: true,
      type: 'inner',
      height: 200
    }
  }

  return (
    <Grid id={'scroll-1'} columns={columns} rows={rows} options={options} />
  )

}

export default ScrollInnerComponent

Previews

THIS WEEK
TITLE
ARTIST
AWARD
LAST WEEK
PEAK POS.

1

Last Night

Morgan Wallen

1

1

2

Flowers

Miley Cyrus

3

1

3

Kill Bill

SZA

4

Calm Down

Rema & Selena Gomez

5

Favorite Song

Toosii

ScrollOuterComponent.tsx
...
const options: IPropsOptions = {
  scroll: {
    enable: true,
    type: 'outer'
  }
}

return (
  <div style={{
    height: '200px',
    overflow: 'auto'
  }>
    <p>...</p>
    <Grid id={'scroll-2'} columns={columns} rows={rows} options={options} />
  </div>
)
...

If you use the outer option, you can control the outer scrolling and the head of the table is sticky.

The height option is not used when outer options are used.

Previews

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.

THIS WEEK
TITLE
ARTIST
AWARD
LAST WEEK
PEAK POS.

1

Last Night

Morgan Wallen

1

1

2

Flowers

Miley Cyrus

3

1

3

Kill Bill

SZA

4

Calm Down

Rema & Selena Gomez

5

Favorite Song

Toosii

AddClassNameByRows

You can assign a className to a specific row via the addClassNameByRows setting. Used to style specific irregular rows.

interface
interface IClassNameByRow {
  index: number
  className: string | Array<string>
}
AddClassComponent.tsx
import React from 'react'
import styled from '@emotion/styled'
import Grid, { GridType, IPropsColumn, RowType, IClassNameByRow } from '@tenqube/react-grid'

const AddClassComponent = () => {

  const columns: Array<IPropsColumn> = [{
    id: 'string',
    name: 'Text',
    type: GridType.String
  }]

  const rows: Array<Array<RowType>> = [[
    'data1'
  ], [
    'data2'
  ], [
    'data3'
  ], [
    'data4'
  ]]

  const addClassNameByRows: Array<IClassNameByRow> = [{
    index: 3,
    className: 'color-red',
  }]

  return (
    <$area>
      <Grid id={'add-class'} columns={columns} rows={rows} addClassNameByRows={addClassNameByRows} />
    </$area>
  )

}

export default AddClassComponent

const $area = styled.div`
  .color-red {
    color: red;
  }
`

The index value starts from 0.

Previews

Text

data1

data2

data3

data4

To add multiple classNames, add objects at the same index.

AddClassComponent.tsx
const addClassNameByRows: Array<IClassNameByRow> = [{
  index: 3,
  className: 'color-red',
}, {
  index: 3,
  className: 'background-black',
}]

...

const $area = styled.div`
  .color-red {
    color: red;
  }
  .background-black {
    background: black;
  }
`

Previews

Text

data1

data2

data3

data4

Building

React Grid only provides very basic functionality. However, it can be developed and extended in many ways.

Styling

A separate method for styling is not supported. Instead, it supports a className that can be distinguished for various items.

{id}-column-{index}

A className is declared for every column according to the grid id and index value of the column. Index starts from 0, and Hidden type columns are not included in the index because they are not displayed.

{GridType}-type

enum
enum GridType {
  Hidden,
  Checkbox,
  String
  Toggle
  Image
  Link
  Button
  Items
  InputText
  InputNumber
  Array
}

A className is declared in the column according to the grid type.
EX. string-type, toggle-type, input-text-type, ...

row-{index}

A className including index is given for each row.

fixed

Columns that are fixed using the fixedSize option are declared with a className of 'fixed'.