DEV Community

Cover image for Check Out My Table Component!
Doug Elkin
Doug Elkin

Posted on

 

Check Out My Table Component!

The latest version of the @preaction/bootstrap-clips package now has a reusable, sortable, filterable, searchable, pageable, and extendable Table component.

That's a lot of adjectives to cover. Let's dive in!

Getting Started

yarn add --dev @preaction/bootstrap-clips \
  bootstrap \
  @popperjs/core
Enter fullscreen mode Exit fullscreen mode

or:

npm install --save-dev @preaction/bootstrap-clips \
  bootstrap \
  @popperjs/core
Enter fullscreen mode Exit fullscreen mode

Note: bootstrap is a peerDependency of this library, and @popperjs/core is a peerDependency of bootstrap.

Example: Users Table

The following example will render a table from the JSON Placeholder /users resource. In addition to the id, name, email, phone, and website attributes, I want the company attribute to reflect company.name from the JSON data. An additional column should also be added for a "View" button. The email and website columns should be rendered with hyperlinks. Each column should be sortable (aside from "View"), filterable, and searchable. By default, the users should be sorted by their id attribute.

import { Table } from '@preaction/bootstrap-clips'

function UserTableExample() {
  const [userHeaders] = React.useState(
    new Map()
      .set('view', 'View')
      .set('id', 'ID')
      .set('name', 'Name')
      .set('email', 'Email')
      .set('phone', 'Phone')
      .set('website', 'Website')
      .set('company', 'Company')
  )
  const [users, setUsers] = React.useState([])

  // fetch rows from API
  React.useEffect(async () => {
    const response = await fetch('https://jsonplaceholder.typicode.com/users')
    if (response.status === 200) {
      const data = await response.json()
      const users = []
      for (let u = 0; u < data.length; u++) {
        users.push(Object.assign(data[u], { company: data[u].company.name }))
      }
      setUsers(users)
    }
  }, [])

  // render
  return (
    <div className='app'>
      <h4>User Table</h4>
      <hr />
      <Table
        headers={userHeaders}
        rows={users}
        theme='light'
        hover
        responsive
        rowKey='id'
        extendRow={row => ({
          email: (
            <a href={`mailto:${row.email}`} onClick={e => e.preventDefault()}>
              {row.email}
            </a>
          ),
          view: (
            <button
              type='button'
              className='btn btn-sm btn-secondary'
              onClick={() => console.log(row)}>
              View
            </button>
          ),
          website: (
            <a
              href={`https://${row.website}`}
              target='_blank'
              rel='noopener noreferrer'
              onClick={e => e.preventDefault()}>
              {row.website}
            </a>
          )
        })}
        filter
        sort={['id', 'name', 'email', 'phone', 'website', 'company']}
        search
        defaultSortKey='id'
      />
    </div>
  )
}
<UserTableExample />
Enter fullscreen mode Exit fullscreen mode

users table preview

This works pretty well, but how does it handle a larger dataset?

Example: Photo Table

The following will render a table for all 5,000 of the items in JSON Placeholder's /photos resource, using pagination of the number specified (in this case, 4). I want only the id, and title columns to be sortable, and only the title column to be searchable. Also, instead of just showing you the url for each row, I want it to render the image's thumbnail within a link that opens the full size image in a new window.

import { Table } from '@preaction/bootstrap-clips'

function PhotoTableExample() {
  const [userHeaders] = React.useState(
    new Map().set('id', 'ID').set('title', 'Title').set('url', 'Image')
  )
  const [photos, setPhotos] = React.useState([])

  // fetch rows from API
  React.useEffect(async () => {
    const response = await fetch('https://jsonplaceholder.typicode.com/photos')
    if (response.status === 200) {
      const data = await response.json()
      setPhotos(data)
    }
  }, [])

  // render
  return (
    <div className='app'>
      <h4>Photo Table</h4>
      <hr />
      <Table
        headers={userHeaders}
        rows={photos}
        theme='light'
        striped
        responsive
        compact
        rowKey='id'
        sort={['id', 'title']}
        search={['title']}
        defaultSortKey='id'
        extendRow={row => ({
          url: (
            <div
              style={{ width: '5rem', height: '5rem' }}
              className='img-thumbnail'>
              <a href={row.url} target='_blank' rel='noopener noreferrer'>
                <img src={row.thumbnailUrl} width='100%' height='100%' />
              </a>
            </div>
          )
        })}
        pagination={4}
      />
    </div>
  )
}
<PhotoTableExample />
Enter fullscreen mode Exit fullscreen mode

photo table preview

There are multiple ways to change pages. You can use the previous/next buttons or change the number input, but my favorite thing about this is the range slider. I like it a lot better than numbered buttons or links for paginated navigation because the interface is consistent regardless of
the number of pages. I'm also quite proud of how blazingly fast the table re-renders when sliding this back and forth.

You can play with these examples along with my other components in this library directly within the documentation, which was generated using React Styleguidist.

Top comments (1)

Collapse
 
erikplachta profile image
Erik Plachta

Thank you for sharing this. Exactly what I was looking for 👌❤️🦄