Chartkick.js is a thin layer over Chart.js, and its value is the data shapes it accepts
Create beautiful charts with one line of JavaScript
At a glance
- What is it?
- A small JavaScript library that renders a chart from an array, an object, a callback or a URL, and can hand the same call to Chart.js, Google Charts or Highcharts. The option list is longer than the API, and the per library capability notes are where the real documentation is.
- Who is it for?
- Adopt Chartkick.js if you want to draw a chart from data you already have without writing a charting configuration by hand, or if you want to switch the underlying library later without rewriting your calls. Do not adopt it if you need a chart type it does not cover or fine control over the rendering library, because the escape hatch is passing options straight through with the library option.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 116 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The API is one constructor per chart type
Chartkick.js creates charts with one line of JavaScript, and the shape of the API is uniform across the chart types.
The first thing is a div, because the library targets the element by id.
<div id="chart" style="height: 300px;"></div>Then a chart constructor with the id and the data.
new Chartkick.LineChart("chart", {"2026-01-01": 11, "2026-01-02": 6})The constructors are `LineChart`, `PieChart`, `ColumnChart`, `BarChart`, `AreaChart`, `ScatterChart`, `GeoChart` and `Timeline`. All of them take the element id and the data, with `PieChart` taking a list of name and value pairs and `ColumnChart` taking a list of label and value pairs.
What matters about the uniformity is what it enables. The same call renders in Chart.js, Google Charts or Highcharts, so the underlying library is a packaging decision rather than an architectural one. The README points at the documentation of each of the three for the options they support.
The one asymmetry is `GeoChart` and `Timeline`, which are marked as Google Charts. The README labels them inline rather than hiding the limitation, which is the right way to handle a gap like that.
There is a companion project for maps, Mapkick.js, linked from the README, which suggests the same one line approach applied to geographic data.
The package is MIT licensed, the version is 5.0.1, and the last push to the repository was on 2026-06-29 with the repository not archived.
Four data shapes, and the choice between them is a performance decision
Data can be an array, an object, a callback, or a URL, and the four cases are not equivalent in what they cost.
The array form is the plain one, a list of date and value pairs.
new Chartkick.LineChart("chart", [["2026-01-01", 2], ["2026-01-02", 3]])The object form is a map from label to value, which is convenient when the data arrives as a dictionary.
new Chartkick.LineChart("chart", {"2026-01-01": 2, "2026-01-02": 3})The callback form takes two functions, a success and a fail, and calls one of them with the data.
function fetchData(success, fail) {
success({"2026-01-01": 2, "2026-01-02": 3})
// or fail("Data not available")
}
new Chartkick.LineChart("chart", fetchData)And the URL form is the interesting one, because the README gives a reason rather than a syntax. Make your pages load super fast and stop worrying about timeouts. Give each chart its own endpoint.
new Chartkick.LineChart("chart", "/stocks")The trade-off is implicit in the sentence. With the URL form the chart renders as soon as the data arrives, so the page is not blocked on the request, but the chart appears empty until then. With the callback form you control both the timing and the error path, and the fail function is what you use to say the data is not available.
The `loading` and `empty` options tie into this. The loading message is what the user sees while the URL request is in flight, and the empty message is what they see when the data comes back with nothing in it. Those two options are the whole user experience of a chart that loads asynchronously, and having them at the same level as the axis options is a good sign about what the library thinks matters.
The option list is long, and each entry names which libraries support it
The options section is the bulk of the README, and its organisation is the interesting part. Options are grouped by what they affect, and each one is annotated with the libraries it works with.
Axis bounds come first, with `min` and `max` for the y-axis, and the note that `min` defaults to 0 for charts with non-negative values, and that you use `null` to let the charting library decide. The x-axis equivalents `xmin` and `xmax` are marked as Chart.js only, which is a real difference between the libraries and exactly the kind of thing the annotation is there to prevent you from assuming.
Colours, `colors`, take an array. Stacking is `stacked: true`, and there is a note that you can also set it to `percent` or `relative` for Google Charts and `percent` for Highcharts, so the option has a different set of legal values per library. A discrete axis is `discrete: true`. A label for a single series is `label`. Axis titles are `xtitle` and `ytitle`.
Then the presentation options. `curve: false` gives straight lines between points instead of a curve. `points: false` hides the points. `legend: true` shows or hides the legend, and `legend: "bottom"` sets its position.
The number formatting options are the ones that come up most in practice. `prefix` is useful for currency and `suffix` for percentages. `thousands` and `decimal` set the separators, which matters as soon as your data is not American formatted. `precision` sets significant digits and `round` sets rounding, with `zeros: true` to show insignificant zeros, again useful for currency. And `bytes: true` gives friendly byte sizes.
Then the ones that are about the data rather than the drawing. The `refresh` option takes a number of seconds and refreshes the data from a remote source on that interval, and it works with the URL form.
Finally the two escape hatches, and they are the ones to know about. The `library` option passes options straight through to the charting library itself, so `library: {backgroundColor: "pink"}` works. And for Chart.js specifically there is a `dataset` option for customising datasets, which can also be passed to individual series.
So when Chartkick runs out of options, it does not run out of library, because the underlying library is still there.
Packaging separates the three libraries into separate entry points
The package metadata explains the install and the design decisions behind it.
Installing means getting the library and the underlying charting library.
npm install chartkick chart.jsThen two imports, where the second one is a side effect import that registers Chart.js with Chartkick.
import Chartkick from "chartkick"
import "chartkick/chart.js"The exports map in the package metadata has a `.` entry with a `require` condition pointing at a CommonJS build and an `import` condition pointing at an ES module build, which is the dual packaging modern bundlers expect. Then there are two subpath exports, `./chart.js` and `./highcharts`, each pointing at an ES module file in the matching top level directory.
Those two directories at the root, `chart.js/` and `highcharts/`, are the adapters. They are shipped in the `files` array alongside `dist`, so the package is three things: the core library and one small adapter per bundled charting integration. That is a clean split, and it is why the install step needs a separate import: the core does not know about any particular library until you tell it.
The optional dependencies make the same point from the other side. `chart.js` at version 4, `chartjs-adapter-date-fns` and `date-fns` are optional rather than required, so installing Chartkick without committing to a charting library is possible, and the README's instruction to install both packages is the recommended path rather than the only one.
The build is Rollup with the terser plugin for minification and the buble plugin for transpilation, at Rollup 4.25.0. The version is 5.0.1, which tells you the 5.x line has been through at least one major revision, and the `CHANGELOG.md` at the root is where the changes are recorded.
The framework wrappers are listed as separate projects, React, Vue.js, Ruby, Python, Elixir and Clojure, and the sibling Mapkick.js is for maps. That spread is the clearest evidence of what this library is for: a thin, portable core that other people wrap.
Global options, per series options, and where the limits are
Two scoping mechanisms are worth understanding because they are the difference between a library that is pleasant to use in a dashboard and one that is not.
The first is global options. To set options for all of your charts you assign to `Chartkick.options`.
Chartkick.options = {
colors: ["#b00", "#666"]
}For a dashboard with a consistent look, that single assignment is the difference between one line of configuration and forty.
The second is per series options, and the README is explicit that you can pass a few options with a series. The multi series example shows why that matters, because the series in it have different meanings and therefore different presentation needs.
data = [
{name: "Workout", data: {"2026-01-01": 3, "2026-01-02": 4}},
{name: "Call parents", data: {"2026-01-01": 5, "2026-01-02": 3}}
]
new Chartkick.LineChart("chart", data)And the stacked example shows the `stack` key on a series, which is how a grouping is expressed. Two series sharing a stack name are stacked together, and the example uses the fruit and vegetable grouping with two series in each.
data = [
{name: "Apple", data: {"Tuesday": 3, "Friday": 4}, stack: "fruit"},
{name: "Pear", data: {"Tuesday": 1, "Friday": 8}, stack: "fruit"},
{name: "Carrot", data: {"Tuesday": 3, "Friday": 4}, stack: "vegetable"},
{name: "Beet", data: {"Tuesday": 1, "Friday": 8}, stack: "vegetable"}
]
new Chartkick.BarChart("chart", data, {stacked: true})The limits are also stated clearly, which is the mark of a library that has been used enough to know where it stops. The `stacked` option takes different values per library. The x-axis bounds are Chart.js only. The `prefix`, `suffix`, `thousands`, `decimal`, `precision`, `round` and `zeros` options are marked as Chart.js and Highcharts. The `bytes` option is Chart.js only. And the `GeoChart` and `Timeline` types are Google Charts only.
So the library is portable in its core and specific in its edges, and the README tells you which edge you are standing on rather than leaving you to find out from a rendering bug.
Editorial conclusion
Adopt Chartkick.js if you want to draw a chart from data you already have without writing a charting configuration by hand, or if you want to switch the underlying library later without rewriting your calls. Do not adopt it if you need a chart type it does not cover or fine control over the rendering library, because the escape hatch is passing options straight through with the library option. Verify first that the underlying library you plan to use is one of the three supported, that the option you need is marked as supported for that library in the README, and that the data shape you have matches one of the four the library accepts.
Frequently asked questions
What charting libraries does Chartkick.js support?
Chart.js, Google Charts and Highcharts, through the same call. The adapters are separate import paths, and you install the underlying library yourself, for example npm install chartkick chart.js followed by importing chartkick and chartkick/chart.js.
What data formats can Chartkick.js charts take?
An array of label and value pairs, an object mapping labels to values, a callback with a success and a fail function, or a URL. The README recommends the URL form so pages load fast and do not have to wait for a timeout.
How do I set options for every chart in Chartkick.js?
Assign them to Chartkick.options, for example Chartkick.options = { colors: ["#b00", "#666"] }. Individual charts can also take options, and a series can carry its own options such as a stack name.
Which Chartkick.js options are not supported by every library?
The README marks xmin and xmax as Chart.js only, bytes as Chart.js only, the prefix, suffix, thousands, decimal, precision, round and zeros options as Chart.js and Highcharts, and GeoChart and Timeline as Google Charts only. The stacked option also takes different values per library.
Can I pass options straight to the underlying charting library in Chartkick.js?
Yes, through the library option, for example new Chartkick.LineChart("chart", data, {library: {backgroundColor: "pink"}}). For Chart.js there is also a dataset option for customising datasets, which can be applied to individual series.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ankane-chartkick-js)Was this useful?