npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@saltyaom/react-table

v1.1.1

Published

Declarative React Table under 1kb.

Downloads

8

Readme

@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.