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 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-likert

v0.8.0

Published

Stylish react + d3 likert renderer for smart use in a table

Readme

React-Likert

npm version

React components for rendering Likert-like visualizations within a table.

View the demo for a few examples.

Why?

While various chart options exist for this kind of survey question, none of them can easily integrate into a true table while offering key features like diverging bars and good defaults. Typically, our survey results will be presented most cleanly in a table format within which the Likert visualization is only one part alongside various other statistics. This tool makes that possible without compromising or splitting between a table and chart.

What?

I've taken a somewhat unorthodox approach to rendering: using the included <TableWrapper/>, you replace the cells in the desired column with the <CellRenderer/> it provides. This renderer creates normal table cells (with aria attributes to indicate the value of the cell for accessiblity), then draws a single svg over that entire table region and animates it with D3. This offers the benefits of a single chart alongside the stability and accessibility of a true table.

How?

A simple syntax example:

import React from 'react'
import { TableWrapper } from 'react-likert'

const scale = [
  'Strongly Disagree',
  'Disagree',
  'Undecided',
  'Agree',
  'Strongly Agree',
]

const data = [
  {
    prompt: 'Likerts are useful', 
    responded: 35,
    'Strongly Disagree': 0.3, 
    'Disagree': 0.25, 
    'Undecided': 0, 
    'Agree': 0.22, 
    'Strongly Agree': 0.23 
  },
  { 
    prompt: 'D3 is still a viable choice in React projects',
    responded: 38,
    'Strongly Disagree': 0.1, 
    'Disagree': 0.22, 
    'Undecided': 0.05, 
    'Agree': 0.45, 
    'Strongly Agree': 0.18 
    },
  // etc
]

const DivergingLikertExample = props => (
  <div>
    <TableWrapper scale={scale}>
      {
        CellRenderer => 
          <table style={{ width: '100%' }}>
            <thead>
              <tr>
                <th style={{textAlign: 'left'}}>prompt </th>
                <th style={{textAlign: 'left', width: '3em'}}>n </th>
                <td style={{width: '50%'}}> </td>                
              </tr>
            </thead>
            <tbody>
              {
                data.map(({ prompt, responded, ...values }, i) => 
                  <tr key={i}>
                    <td>{prompt}</td>
                    <td>{responded}</td>
                    <CellRenderer value={values} />
                  </tr>
              )}
            </tbody>
          </table>
      }
    </TableWrapper>
  </div>
)

Components

<TableWrapper>

Required as parent of the <table> you will draw; requires a scale prop at minium (with a flat list of Likert choices in the order you wish them displayed), but will also accept options object (see section below). Provides a CellRenderer to its child (in the render-prop or function-as-child pattern), which will be bound to this table context so that rendering of each Likert can be coordinated as a single visualization.

<TableWrapper scale={scale} options={{ usePatterns: false }}>
  {CellRenderer => 
      <table>
        ... // see below for usage of CellRenderer  
      </table>
  }
</TableWrapper>

Note that the scale is assumed to be a symmetrical Likert (unless using continuous: true option; see below), so that the positive / negative values divide either evenly or with a "neutral" middle term when the count is odd.

Example scales:

[ 'Strongly Disagree', 'Disagree', 'Undecided', 'Agree', 'Strongly Agree' ]
[ 'Very Unlikely', 'Unlikely', 'Likely', 'Very Likely' ]

<CellRenderer>

This component is not a direct export of the library, and is provided only by the TableWrapper invoked as shown above. Use it to render the entire table cell where you want the Likert, passing a value object with keys matching the scale you passed to the TableWrapper, as floats adding up to 1.

{CellRenderer => 
  <table>
    <thead>
      <tr>
        <th>prompt </th>
        <th>result </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Is this library useful?</td>
        <CellRenderer value={{"Disagree": 0.23, "Agree": 0.77 }} />
      </tr>
      <tr>
        <td>Would you recommend it?</td>
        <CellRenderer value={{"Disagree": 0.55, "Agree": 0.45 }} />
      </tr>
    </tbody>
  </table>
}

<LikertLegend>

Draws a simple legend for your Likert, for use outside of the table. Requires the scale, optionally accepts inline (Boolean; if true, renders as spans inline), a size in pixels for the squares, and any additional styles to apply.

<LikertLegend
  scale={scale}
  inline={true}
  size={12}
  style={{ textAlign: 'right' }}
/>

Options

The options object should be passed as a prop to the <TableWrapper>, and offers a number of customizations (see examples and their source code for context).

| Key | Type | Description | | -------------- | ---------------------------- | ------------------------------------------------------------------ | | diverging | Boolean | Whether to draw as diverging bars; if false, renders as normal stacked. | | usePatterns | Boolean | By default, patterns are applied to the segments; pass false to disable.| | continuous | Boolean | If set to true, a continuous scale will be drawn (no pos/neg polarity). | | colors | Array | Custom colors; the order depends on the type of chart, see below. |

The colors take one of two forms. For the default diverging type of chart, you must pass three items with two nested arrays:

[ neutral, [left-main, left-highlight], [right-main, right-highlight]]

e.g. ['#888', ['#800e84', '#ad72b5'], ['#006f30','#48bf6f']]

For a "continuous" chart, where the scale does not have a left / right polarity and simply increases, you only pass two values:

[ left, right ]

e.g. ['#eeeeee', '#995555']

Once again, check the examples for usage in context.