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-metabase-charts

v0.1.4

Published

Render Metabase dashboards and charts in React using MUI v7 and Recharts, with full layout customization.

Readme

react-metabase-charts

Drop your Metabase dashboards and charts straight into any React app — and keep full control over how they look and behave. No iframes, no copy-pasting chart code.

Instead of embedding Metabase inside a frame, react-metabase-charts talks directly to Metabase's REST API, which is available in the free / Community edition. You get the data, and you decide how it's presented: every chart and every dashboard layout is built from your own components, styled with MUI sx, and driven by your filters. That level of customization simply isn't possible with embeds.

What it does for you

  • Full customization instead of embeds — you render the charts yourself and style every part, so dashboards blend seamlessly into your app instead of looking like a Metabase page in a box. (Embedding via iframe is a paid Metabase feature; this library uses the open Community API.)
  • Total control — choose where charts go, how big they are, what the filters look like, and even render your own filter UI. You're never locked into Metabase's layout.
  • Renders an entire dashboard by id, laid out in a responsive grid, with working filters.
  • Renders a single chart by dashboard + card id — live from Metabase, or straight from data you already have.
  • Handles filters for you: Metabase parameters are mapped to each card's query automatically, including "chained" filters (picking one filter limits the options of the next).
  • Looks great everywhere — layouts and charts adapt to phones.
  • Lets people export any chart as CSV or PNG from the card header.

Installation

npm install react-metabase-charts

This package doesn't bundle React, MUI, Recharts, etc. — you install those yourself (faster installs, no version conflicts). Make sure your app already has:

react  react-dom  @mui/material  @mui/icons-material
@emotion/react  @emotion/styled  recharts (^3.x)  html2canvas

The 30-second setup

One small step before anything works: tell the library how to reach your Metabase by wrapping your app (or just the page that uses it) in MetabaseProvider.

import { MetabaseProvider, MetabaseDashboard } from 'react-metabase-charts';

function App() {
  return (
    <MetabaseProvider
      config={{
        baseUrl: 'https://metabase.example.com', // your Metabase instance
        username: 'mb_user',
        password: 'mb_pass',
      }}
    >
      <MetabaseDashboard dashboardId={42} />
    </MetabaseProvider>
  );
}

That's it — a full, filterable dashboard. (The credentials are only used in the visitor's browser to get a Metabase session token; they're not exposed on every request.)

Recommended: token-based auth (no credentials in the browser)

Sending a Metabase username/password from the browser ships those credentials into your JS bundle. Prefer having your backend mint the session token and pass a getSessionToken callback instead — the browser only ever holds a short-lived Metabase session token:

<MetabaseProvider
  config={{
    baseUrl: 'https://metabase.example.com',
    getSessionToken: async () => {
      const res = await fetch('/api/metabase-token', {
        headers: { Authorization: `Bearer ${localStorage.getItem('token')}` },
      });
      return (await res.json()).id; // your backend returns { id: <metabase session> }
    },
  }}
>
  <MetabaseDashboard dashboardId={42} />
</MetabaseProvider>

The token is fetched lazily and refreshed by the library when it approaches expiry, so the shared Metabase credentials stay server-side.

Tip: the username/password mode below has no token callback and is meant for throwaway/local setups — the credentials then travel in your bundle.


Common ways to use it

1. A whole dashboard, ready to go

The simplest option, shown above. Add a couple of props to take control:

<MetabaseDashboard
  dashboardId={42}
  restrictedFilters={{ regiao: ['Sudeste'] }} // pre-applied + can't be removed by users
  hiddenParams={['senha_interna']}            // params you don't want shown at all
  filterLayout="bar"                          // see "Filter UIs" below
/>

2. Just one chart on a page

Say you only want a single card from inside a dashboard:

import { MetabaseChart } from 'react-metabase-charts';

<MetabaseChart dashboardId={42} cardId={7} filters={{ regiao: ['Sudeste'] }} />

It fetches that card, applies your filters, and renders it.

3. Render data you already have

Already have the data? Skip the network — just hand it over. Tell it what type of chart to draw (line, bar, pie, ...):

<MetabaseChart
  data={[
    { mes: 'jan', total: 120 },
    { mes: 'fev', total: 90 },
  ]}
  metabaseDisplayType="line"
/>

Filter UIs (choose your flavor)

Dashboard filters can be shown a few ways. Set filterLayout:

| filterLayout | What the user sees | | --- | --- | | both (default) | a chip bar of active filters plus a Filtrar button that opens a slide-out drawer | | bar | just the horizontal chip bar of active filters | | drawer | just the floating Filtrar button + drawer | | custom | none of the built-in UI — you render your own |

Building your own filter UI? Pass renderCustomFilters. You get all the internal state and fetching (including chained values) and you decide how it looks:

<MetabaseDashboard
  dashboardId={42}
  filterLayout="custom"
  renderCustomFilters={({ parameters, filters, setFilters, clearFilters, activeSlugs }) => (
    <div>
      {parameters.map((param) => (
        <button
          key={param.id}
          onClick={() => setFilters({ ...filters, [param.slug]: ['X'] })}
        >
          Filter by {param.name}
        </button>
      ))}
      <button onClick={clearFilters}>Clear</button>
    </div>
  )}
/>

Styling

Every piece of the UI accepts MUI sx props, so you can match your app's look:

<MetabaseDashboard
  dashboardId={42}
  sx={{ backgroundColor: 'transparent' }} // outer container
  gridSx={{ gap: '16px' }}
  cardSx={{ borderRadius: '8px' }}
  filterBarSx={{}}
  drawerSx={{}}
/>

Full layout theming with layoutSx

On top of the convenience props above, MetabaseProvider, MetabaseDashboard and MetabaseChart accept a layoutSx map that overrides every presentational wrapper/container slot (dashboard container, grid, cards, filter bar, filter drawer, FAB, chart wrappers, scalar, skeleton, …). It merges on top of the built-in defaults, so you only set the slots you want to change:

<MetabaseDashboard
  dashboardId={42}
  layoutSx={{
    container: { backgroundColor: 'transparent', p: 0 },
    card: { borderRadius: 8, boxShadow: 1 },
    cardHeader: { borderBottom: 'none' },
    chartContent: { height: 280 },
    scalarValue: { fontSize: '3.5rem', color: 'primary.main' },
    filterChip: { bgcolor: 'grey.100' },
  }}
/>

layoutSx scopes as it nests: MetabaseProvider sets app-wide defaults, an inner MetabaseDashboard/MetabaseChart narrows/overrides them for its subtree, and every slot not provided keeps the library default. Overrides are plain values evaluated against your ambient MUI theme — they are not a MUI theme merger and do not touch other providers (e.g. drf-react-by-schema). The full list of slots lives in the MetabaseLayoutSx type.

Mobile detection uses your MUI theme's md breakpoint by default. To detect with your own theme (or force a value), pass theme/isMobile to MetabaseProvider.


Hooks (when you want to build your own UI)

Prefer full control? MetabaseProvider also exports two hooks you can call anywhere under it:

import { useMetabaseDashboard } from 'react-metabase-charts';

function MyPage() {
  const { schema, cardsData, filters, setFilters, error, isEmpty, hasErrors } =
    useMetabaseDashboard(42, { regiao: ['Sudeste'] });

  // schema.cardSchemas, cardsData[cardId].data / .loading / .error ...
}
  • useMetabaseDashboard(dashboardId, restrictedFilters?) — the whole dashboard's schema, per-card data, filter state and errors.
  • useMetabaseChart(dashboardId, cardId, filters) — one card's schema + data + loading/error.

No data or charts not loading? A quick checklist

  • Missing provider — any MetabaseDashboard, MetabaseChart, or the export buttons must live under a MetabaseProvider. You'll get a clear error if they don't.
  • Wrong id — double-check the dashboardId / cardId against Metabase.
  • Credentials — the session token comes from config.username/password. Wrong credentials show up as an auth error in the console.
  • Server reachable — the browser must be able to reach config.baseUrl. Watch the Network tab for /api/session and /api/dashboard/... calls.
  • Empty results — a card with no matching rows shows "Não há dados disponíveis". That's expected, not a bug.

License

AGPL-3.0-or-later.