@saltyaom/react-table
    TypeScript icon, indicating that this package has built-in type declarations

    1.1.1 • Public • Published

    @saltyaom/react-table

    Declarative React Table under 1kb.

    Polka Drake

    Humanity Restored

    Feature

    • No dependencies.
    • Light, 700 bytes on production.
    • Easy to understand, declarative.
    • Automatic key management.
    • Full control over table.
    • Full TypeScript support.

    Size

    Should be around 700 bytes, checkout Bundlephobia for accurate result.

    Getting start

    yarn add @saltyaom/react-table
    
    // Or npm
    npm install @saltyaom/react-table --save

    Example

    import Table from '@saltyaom/react-table'
    
    const Example = () => {
        return (
            <Table
                header={['name', 'detail']}
                dataKey='name'
                data={[
                    ['Fubuki', 'Waifriend'],
                    ['Korone', 'Yubi yubi']   
                ]}
            />
        )
    }

    Why

    Compose React table in a simple, elegant way.

    Creating table in React is complicate.

    Let create a simple table from the following data.

    name type value
    Okayu cat 1
    Korone dog -1

    Where the requirement is:

    • First field on table head is bold.
    • Value field must be color by the following:
      • if value >= 0, return green
      • otherwise, return red

    Implement on normal React would be like:

    const VTuberTable = () => {
        const header = ['name', 'description', 'value']
        const data = [
            ['Okayu' , 'cat', 10],
            ['Korone', 'dog', -1]
        ]
    
        return (
            <table>
                <thead className="head">
                    <tr>
                        {header.map((title, index) => {
                            if(index === 0) return <th className="title bold">{title}</th>
    
                            return (
                                <th className="title">{title}</th>
                            )
                        })}
                    </tr>
                </thead>
                <tbody className="body">
                    {data.map(row => 
                        <tr key={row[0]}>
                            {row.map((data, index) => {
                                if(data === 2)
                                    if(data >= 0)
                                        return (
                                    <td 
                                        key={`${row[0]}-${index}-${data}`} 
                                        className="green"
                                    >
                                        {data}
                                    </td>
                                )
                                    else
                                        return (
                                    <td 
                                        key={`${row[0]}-${index}-${data}`} 
                                        className="red"
                                    >
                                        {data}
                                    </td>
                                )
    
                                return (
                                    <td 
                                        key={`${row[0]}-${index}-${data}`} 
                                        className="black"
                                    >
                                        {data}
                                    </td>
                                )
                            })}
                        </tr>
                    )}
                </tbody>
            </table>
        )
    }

    The problem is:

    • The code is very long.
    • Semantic table require a lot of boilerplate, thead, tr, table.
    • Hard to understand, imperative.
    • key managment is complex.

    Entering @saltyaom/react-table

    @saltyaom/react-table is a simple, declarative way to compose table in React.

    All you need to do is specified your data and key, you can bring your className anywhere, even a custom condition for class.

    In the other word, you have full control over the table even in a declarative way.

    Let's re-implement previous table in @saltyaom/react-table.

    import Table from '@saltyaom/react-table'
    
    const VTuberTable = () => {
        const header = ['name', 'description', 'value']
        const data = [
            ['Okayu' , 'cat', 10],
            ['Korone', 'dog', -1]
        ]
    
        return (
            <Table 
                dataKey="name"
                header={header}
                data={data}
    
                theadClassName="head"
                tbodyClassName="body"
    
                // Apply 'title' to all <th> element
                allThClassName="title"
                // Apply 'bold' to index 0 <th>
                thClassName={['bold']}
    
                tdClassName={[
                    '',
                    '',
                    // On index 2, apply custom condition
                    (value: number) => value >= 0 ? 'green' : 'red'
                ]}
            />
        )
    }

    That's it, we have a simple happy ending for composing table in React.

    Documentation

    Table is the only export and is default export from @saltyaom/react-table.

    The acceptable props is:

    export interface ITable<
    	T =
    		| (string | number | JSX.Element)[]
    		| readonly (string | number | JSX.Element)[]
    > {
    	/**
    	 * Table header to be appear in `<thead>` in order.
    	 *
    	 * @example
    	 * ['name', 'description']
    	 */
    	header: T
    
    	/**
    	 * Data to be appear for each row `<td>` in order.
    	 *
    	 * @example
    	 * [
    	 *  ['Korone', 'Dog'],
    	 *  ['Okayu', 'Cat']
    	 * ]
    	 */
    	data: T[] | readonly T[]
    
    	/**
    	 * Key of data, can be either `string` which match in `header` or number as index.
    	 *
    	 * @example
    	 * 0
    	 *
    	 * @example
    	 * 'name'
    	 */
    	dataKey?: string | number
    
    	/**
    	 * className of wrapper of `<table>`
    	 * (element: `<section>`)
    	 */
    	wrapperClassName?: string
    	/**
    	 * className of `<table>`
    	 */
    	className?: string
    	/**
    	 * Width of each cell in order from left to right.
    	 *
    	 * @example
    	 * [80, 160]
    	 */
    	cellsWidth?: number[]
    
    	/**
    	 * className of `<thead>`
    	 */
    	theadClassName?: string
    	/**
    	 * className of `<th>`
    	 */
    	thClassName?: string[]
    	/**
    	 * className to apply to all `<th>`
    	 */
    	allThClassName?: string
    
    	/**
    	 * className of `<tbody>`
    	 */
    	tbodyClassName?: string
    	/**
    	 * className of `<td>`
    	 *
    	 * Can be either `string` or `function()` which accepts `([valueof data:, index: number])`
    	 *
    	 * @example
    	 * w-8
    	 *
    	 * @example
        // If nothing is returned, fallback to ''
    	 * (rowData, index) => {
    	 *  if(rowData.value === 0) return 'bg-blue-50'
    	 *  if(rowData.index === 0) return 'bg-red-50'
    	 * }
    	 */
    	trClassName?: string | ((data: readonly T[], index: number) => string)
    	/**
    	 * className of `<td>`
    	 *
    	 * Can be either `string[]` or `function()` which accepts `([valueof data:, index: number])`
    	 *
    	 * @example
    	 * ['w-8', 'w-16']
    	 *
    	 * @example
        // If nothing is returned, fallback to ''
    	 * (value, index) => {
    	 *  if(value === 0) return 'text-red-500'
    	 *  if(index === 0) return 'text-blue-500'
    	 * }
    	 */
    	tdClassName?:
    		| (string | ((data: any, index: number) => string))[]
    		| ((data: string, index: number) => string)
    	/**
    	 * className to apply to all `<tbody>`
    	 */
    	allTdClassName?: string
    
    	/**
    	 * Prepend element before table
    	 *
    	 * @example
    	 * <nav>
    	 * 	 <input
    	 * 	   name="search"
    	 * 	   type="text"
    	 *     placeholder="Search"
    	 *     onChange={handleSearch}
    	 *   />
    	 * </nav>
    	 */
    	beforeTable?: JSX.Element
    	/**
    	 * Append element after table
    	 *
    	 * @example
    	 * <section className="pagination">
    	 * 	<button className="prev" onClick={previous}>Previous</button>
    	 * 	<button className="next" onClick={next}>Next</button>
    	 * </section>
    	 */
    	afterTable?: JSX.Element
    
    	/**
    	 * Add custom props to `<table>` element
    	 *
    	 * @example
    	 * {
    	 *   style={
    	 *     borderCollapse: 'collapse'
    	 *   }
    	 * }
    	 */
    	tableProps?: Omit<
    		DetailedHTMLProps<
    			TableHTMLAttributes<HTMLTableElement>,
    			HTMLTableElement
    		>,
    		'className'
    	>
    
    	/**
    	 * Add custom props to `<thead>` element
    	 *
    	 * @example
    	 * {
    	 *   onClick: () => console.log("Clicked")
    	 * }
    	 */
    	theadProps?: Omit<
    		DetailedHTMLProps<
    			HTMLAttributes<HTMLTableSectionElement>,
    			HTMLTableSectionElement
    		>,
    		'className'
    	>
    	/**
    	 * Add custom props to `<th>` element
    	 *
    	 * @example
    	 * (data, index) => {
    	 *   if(isOdd(index)) return ({ className: '--odd' })
    	 * }
    	 */
    	thProps?: (
    		data: T[keyof T],
    		index: number
    	) => Omit<
    		DetailedHTMLProps<
    			ThHTMLAttributes<HTMLTableHeaderCellElement>,
    			HTMLTableHeaderCellElement
    		>,
    		'className'
    	> | void
    	/**
    	 * Add custom props to `<tbody>` element
    	 *
    	 * @example
    	 * {
    	 *   onClick: (data, index) => console.log("Clicked")
    	 * }
    	 */
    	tbodyProps?: Omit<
    		DetailedHTMLProps<
    			HTMLAttributes<HTMLTableSectionElement>,
    			HTMLTableSectionElement
    		>,
    		'className'
    	>
    	/**
    	 * Add custom props to `<tr>` element
    	 *
    	 * @example
    	 * (data, index) => {
    	 *   if(isOdd(index)) return ({ className: '--odd' })
    	 * }
    	 */
    	trProps?: (
    		row: T,
    		index: number
    	) => Omit<
    		DetailedHTMLProps<
    			HTMLAttributes<HTMLTableRowElement>,
    			HTMLTableRowElement
    		>,
    		'className'
    	> | void
    	/**
    	 * Add custom props to `<td>` element
    	 *
    	 * @example
    	 * (data, { column, row }) => ({
    	 *   onClick: () => console.log(column, row)
    	 * })
    	 */
    	tdProps?: (
    		data: T[keyof T],
    		indexes: {
    			column: number
    			row: number
    		}
    	) => Omit<
    		DetailedHTMLProps<
    			TdHTMLAttributes<HTMLTableDataCellElement>,
    			HTMLTableDataCellElement
    		>,
    		'className'
    	> | void
    }

    For more information, you can looks directly in the source code as it's very easy to read.

    Install

    npm i @saltyaom/react-table

    DownloadsWeekly Downloads

    16

    Version

    1.1.1

    License

    MIT

    Unpacked Size

    98.5 kB

    Total Files

    25

    Last publish

    Collaborators

    • aomkirby123