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

@ministicdev/fabkit

v0.0.4

Published

A floating action button toolkit for React Native + Expo — one action pinned over content, or a speed dial that unfolds in a column or an arc.

Downloads

40

Readme

fabkit

npm version license

A floating action button toolkit for React Native + Expo. One action pinned over the content, or a speed dial that unfolds behind it — in a straight column or a bending arc. The whole dial runs off a single shared value on the UI thread.

import { Fab } from '@ministicdev/fabkit'

<Fab placement="bottom-right" icon={<PlusIcon size={24} />} accessibilityLabel="New note" onPress={compose} />

Install

npm install @ministicdev/fabkit
npx expo install react-native-reanimated

react-native-reanimated (≥3.10) is the one required peer — add its Babel plugin last in babel.config.js:

plugins: ['react-native-reanimated/plugin']

Optional, only if you use the matching prop:

  • haptics → npx expo install expo-haptics
  • blur → npx expo install expo-blur

Both are silent no-ops when absent.


Composition

{/* on its own */}
<Fab icon={…} accessibilityLabel="…" onPress={…} />

{/* or with a dial behind it */}
<Fab.Group icon={…} accessibilityLabel="…" dial="arc">
  <Fab.Action icon={…} label="…" onPress={…} />
  <Fab.Action icon={…} label="…" onPress={…} />
</Fab.Group>

Fab.Action only works inside a Fab.Group — it reads the dial's open progress to know when to unfold, and throws outside one.


The dial: column, arc, or wheel

Fab.Group takes a dial prop:

<Fab.Group dial="column" …>  {/* default — actions stack straight up */}
<Fab.Group dial="arc" …>     {/* actions fan out along a bend around the trigger */}
<Fab.Group dial="wheel" …>   {/* a spinnable ring you grab-and-turn */}

arc sweeps the actions into the free space next to the corner — up-and-left from a bottom-right trigger, up-and-right from bottom-left, and a symmetric fan from bottom-center. Either way it's one animation: a single shared value the actions each take their staggered share of, so opening and closing never fall out of step.

<Fab.Group icon={<PlusIcon size={24} />} accessibilityLabel="Add" dial="arc" blur>
  <Fab.Action icon={<ImageIcon size={18} />} label="Photo" onPress={addPhoto} />
  <Fab.Action icon={<PaperclipIcon size={18} />} label="Attachment" onPress={attach} />
  <Fab.Action icon={<MicIcon size={18} />} label="Voice note" onPress={record} />
  <Fab.Action icon={<TrashIcon size={18} />} label="Empty drafts" destructive onPress={empty} />
</Fab.Group>

Opening drops a scrim (or a blur) over the screen — the dial is modal, so the next tap either picks something or closes it, and the scrim is what says so and catches the tap. rotateOnOpen turns the trigger's glyph a quarter turn, so a plus becomes a close-cross.

wheel — a spinnable ring

wheel lays the actions on an arc orbiting the trigger and lets you grab and spin them, with momentum, so the ring can hold more items than the arc shows at once — the next one peeks in at each edge to say there's more.

<Fab.Group icon={<CompassIcon size={24} />} accessibilityLabel="Discover" dial="wheel" modal={false}>
  <Fab.Action icon={<DexIcon size={22} />} onPress={openDex} />
  <Fab.Action icon={<PumpIcon size={22} />} onPress={openPump} />
  <Fab.Action icon={<GmgnIcon size={22} />} onPress={openGmgn} />
  {/* …add as many as you like — spin to reach them */}
</Fab.Group>
  • Needs react-native-gesture-handler (optional peer) for the spin — install it and wrap your app in GestureHandlerRootView. Without it the ring still opens, just static.
  • Pair with modal={false} for a non-modal ring: only the ring's corner catches the spin, so the content behind keeps scrolling. Item labels are omitted on a wheel; wheelRadius tunes the orbit size.

Examples

Over a list

The case it exists for. placement pins it to a corner of the nearest positioned ancestor — on a screen, the screen. Give the list enough bottom padding to scroll clear of it.

<View style={{ flex: 1 }}>
  <ScrollView contentContainerStyle={{ paddingBottom: 96 }}>{/* …rows… */}</ScrollView>

  <Fab
    placement="bottom-right"
    icon={<PlusIcon size={24} />}
    accessibilityLabel="New note"
    haptics
    onPress={compose}
  />
</View>

Spelling the action out

extended turns the circle into a stadium with a label beside it — worth the width for anything a plus wouldn't have said.

<Fab extended placement="bottom-right" icon={<PencilIcon size={20} />}>Write</Fab>

In the flow instead of over it

Leave placement out and it's an ordinary round button where you put it — for laying several side by side.

<View style={{ flexDirection: 'row', gap: 16 }}>
  <Fab icon={<PlusIcon size={20} />} accessibilityLabel="Add" />
  <Fab variant="surface" icon={<SearchIcon size={20} />} accessibilityLabel="Search" />
  <Fab variant="destructive" icon={<TrashIcon size={20} />} accessibilityLabel="Delete" />
</View>

Sizes & variants

size is sm | md | lg (md default) — the diameter; the glyph inside it is yours to scale. variant is primary | secondary | surface | destructive (primary default).


Props

Fab

| Prop | Type | Default | Notes | |---|---|---|---| | icon | ReactNode | — | The glyph. Sized by you. | | extended | boolean | false | Stadium shape + label (children). | | placement | 'bottom-left' \| 'bottom-center' \| 'bottom-right' | — | Pin to a corner. Omit for an in-flow button. | | offset | number | 16 | Distance from the edges when placed. Add your safe-area inset. | | size / variant | FabSize / FabVariant | md / primary | | | onPress disabled | | | | | haptics | boolean | false | A tick on press (needs expo-haptics). | | accessibilityLabel | string | — | Required for an icon-only button. | | colors | Partial<FabColors> | — | Theme any part. |

Fab.Group

| Prop | Type | Default | Notes | |---|---|---|---| | dial | 'column' \| 'arc' | 'column' | How the actions unfold. | | icon / label | ReactNode / string | — | Trigger glyph; label extends it while closed. | | open / onOpenChange | boolean / (open) => void | — | Controlled open state. | | placement offset size variant | | bottom-right 16 md primary | Which corner the dial parks in. | | blur | boolean | false | Frost the screen behind the dial (needs expo-blur). | | rotateOnOpen | boolean | true | Turn the trigger glyph a quarter turn (plus → cross). | | haptics disabled colors | | | | | accessibilityLabel | string | — | Required — the trigger is a lone glyph until opened. |

Fab.Action

| Prop | Type | Notes | |---|---|---| | icon / label | ReactNode / string | The glyph, and what it does beside it. | | onPress disabled | | | | destructive | boolean | The destructive colour, for the one that removes something. |


Notes

  • Write a group in the screen's root container. Fab.Group draws its scrim and its buttons as absolutely positioned siblings in whatever it's written inside — that parent is what offset is measured from and what the scrim covers, so it should be the view that fills the screen. This is also what makes the dial belong to its screen: push a new screen over this one and the dial hides with it.
  • Add your safe-area inset to offset to clear the home indicator.
  • Pressing an action closes the dial, and the Android back button closes it rather than popping the screen.
  • The actions are unmounted while closed — not hidden — so a screen reader never walks into buttons nobody can see.
  • One timing, not one per action. The whole dial runs off a single shared value; each action derives its own share on the UI thread from its index, so there's no chain of timeouts to fall out of step.

License

MIT. An original implementation; its API is modeled on panelui-native's Fab, rebuilt on Reanimated with an added arc dial. See LICENSE.