FeatureDrop — Product Adoption Toolkit
Open-source, zero-dependency library for in-app feature discovery. < 3 kB core.
Setup Pattern
npm install featuredrop
- Create a JSON manifest:
[{ id, label, description, releasedAt, showNewUntil? }]
- Wrap root:
<FeatureDropProvider manifest={features} storage={new LocalStorageAdapter()}>
- Add components or use headless hooks.
Imports (ALWAYS use subpath imports)
// Core (no React, no UI)
import { isNew, getNewFeatures, createManifest, LocalStorageAdapter } from 'featuredrop'
// React components (ready-made UI)
import { NewBadge, ChangelogWidget, Tour, Checklist, Banner, Toast } from 'featuredrop/react'
// Headless hooks (data + actions, no JSX — for custom design systems / shadcn)
import { useChangelog, useNewFeature, useNewCount, useTour, useChecklist } from 'featuredrop/react/hooks'
// Storage adapters
import { PostgresAdapter, RedisAdapter, IndexedDBAdapter, HybridAdapter } from 'featuredrop/adapters'
// Validation
import { validateManifest } from 'featuredrop/schema'
// Testing helpers
import { createMockManifest, createMockStorage, TestProvider } from 'featuredrop/testing'
// Tailwind plugin
import { featureDropPlugin } from 'featuredrop/tailwind'
Hooks (prefer these for custom UI / shadcn projects)
| Hook |
Returns |
useNewFeature(id) |
{ isNew, feature, dismiss } |
useNewCount() |
number — unread badge count |
useChangelog() |
{ features, newFeatures, newCount, dismiss, dismissAll, markAllSeen, getByCategory } |
useTour(id) |
{ currentStep, stepIndex, totalSteps, isActive, start, next, prev, skip, complete, goTo } |
useChecklist(id) |
{ tasks, completedCount, totalCount, progress, isComplete, completeTask, resetTask } |
useSurvey(id) |
{ isVisible, questions, submit, askLater, dismiss } |
useFeatureDrop() |
Full provider context (features, count, dismiss, throttle controls, engine) |
useTabNotification() |
Browser tab title: "(3) My App" |
Components (ready-made UI)
NewBadge, ChangelogWidget, ChangelogPage, Tour, Checklist, Spotlight, SpotlightChain,
Hotspot, TooltipGroup, Banner, Toast, AnnouncementModal, Survey, FeedbackWidget,
FeatureRequestButton, FeatureRequestForm
Feature Manifest Format
{
id: string // unique identifier
label: string // display title
description: string // what changed
releasedAt: string // ISO date
showNewUntil?: string // ISO date — auto-expire badge
category?: string // group: "ui", "api", "billing"
type?: string // "feature" | "improvement" | "fix" | "deprecation"
priority?: string // "low" | "medium" | "high" | "critical"
cta?: { label: string; url: string }
audience?: Record<string, string[]> // user segmentation
}
Storage Adapters
Default: LocalStorageAdapter (browser). Server: PostgresAdapter, RedisAdapter.
Offline: IndexedDBAdapter. Hybrid: HybridAdapter (local + remote sync).
Custom: implement { getWatermark, setWatermark, getDismissedIds, addDismissedId }.
Provider Props
<FeatureDropProvider
manifest={features} // required
storage={adapter} // required
analytics={{ onFeatureSeen, onFeatureDismissed, onFeatureClicked }}
userContext={{ plan, role, region }} // for audience targeting
appVersion="2.1.0" // semver gating
throttle={{ maxToastsPerSession: 3, modalCooldownMs: 120_000 }}
locale="en" // i18n (en/es/fr/de/pt/zh-cn/ja/ko/ar/hi)
animation="normal" // "none" | "subtle" | "normal" | "playful"
engine={engineInstance} // optional: FeatureDropEngine for smart delivery
/>
Tailwind Integration
// tailwind.config.ts
import { featureDropPlugin } from 'featuredrop/tailwind'
export default {
plugins: [featureDropPlugin({ prefix: 'fd' })],
}
// Adds: fd-badge, fd-badge-dot, fd-badge-count, fd-animate-pulse, fd-animate-fade-in
// CSS vars: --fd-new, --fd-changelog-bg, --fd-tour-bg (auto dark mode)
Rules
- Always use subpath imports (
featuredrop/react, not just featuredrop)
- Prefer hooks from
featuredrop/react/hooks when the project uses shadcn, Radix, or custom design system
- Features auto-expire via
showNewUntil — don't build manual expiry logic
- Zero production dependencies — don't add external deps
- TypeScript strict mode — no
any types
- All components support headless mode via render props
- Core < 3 kB, React ~12 kB, fully tree-shakeable
1---2name: featuredrop-setup3description: Configure FeatureDrop product adoption toolkit in any project. Use when adding changelogs, feature badges, onboarding tours, checklists, hotspots, feedback widgets, or surveys to an application.4---56# FeatureDrop — Product Adoption Toolkit78Open-source, zero-dependency library for in-app feature discovery. < 3 kB core.910## Setup Pattern11121. `npm install featuredrop`132. Create a JSON manifest: `[{ id, label, description, releasedAt, showNewUntil? }]`143. Wrap root: `<FeatureDropProvider manifest={features} storage={new LocalStorageAdapter()}>`154. Add components or use headless hooks.1617## Imports (ALWAYS use subpath imports)1819```ts20// Core (no React, no UI)21import { isNew, getNewFeatures, createManifest, LocalStorageAdapter } from 'featuredrop'2223// React components (ready-made UI)24import { NewBadge, ChangelogWidget, Tour, Checklist, Banner, Toast } from 'featuredrop/react'2526// Headless hooks (data + actions, no JSX — for custom design systems / shadcn)27import { useChangelog, useNewFeature, useNewCount, useTour, useChecklist } from 'featuredrop/react/hooks'2829// Storage adapters30import { PostgresAdapter, RedisAdapter, IndexedDBAdapter, HybridAdapter } from 'featuredrop/adapters'3132// Validation33import { validateManifest } from 'featuredrop/schema'3435// Testing helpers36import { createMockManifest, createMockStorage, TestProvider } from 'featuredrop/testing'3738// Tailwind plugin39import { featureDropPlugin } from 'featuredrop/tailwind'40```4142## Hooks (prefer these for custom UI / shadcn projects)4344| Hook | Returns |45|------|---------|46| `useNewFeature(id)` | `{ isNew, feature, dismiss }` |47| `useNewCount()` | `number` — unread badge count |48| `useChangelog()` | `{ features, newFeatures, newCount, dismiss, dismissAll, markAllSeen, getByCategory }` |49| `useTour(id)` | `{ currentStep, stepIndex, totalSteps, isActive, start, next, prev, skip, complete, goTo }` |50| `useChecklist(id)` | `{ tasks, completedCount, totalCount, progress, isComplete, completeTask, resetTask }` |51| `useSurvey(id)` | `{ isVisible, questions, submit, askLater, dismiss }` |52| `useFeatureDrop()` | Full provider context (features, count, dismiss, throttle controls, engine) |53| `useTabNotification()` | Browser tab title: `"(3) My App"` |5455## Components (ready-made UI)5657NewBadge, ChangelogWidget, ChangelogPage, Tour, Checklist, Spotlight, SpotlightChain,58Hotspot, TooltipGroup, Banner, Toast, AnnouncementModal, Survey, FeedbackWidget,59FeatureRequestButton, FeatureRequestForm6061## Feature Manifest Format6263```ts64{65 id: string // unique identifier66 label: string // display title67 description: string // what changed68 releasedAt: string // ISO date69 showNewUntil?: string // ISO date — auto-expire badge70 category?: string // group: "ui", "api", "billing"71 type?: string // "feature" | "improvement" | "fix" | "deprecation"72 priority?: string // "low" | "medium" | "high" | "critical"73 cta?: { label: string; url: string }74 audience?: Record<string, string[]> // user segmentation75}76```7778## Storage Adapters7980Default: `LocalStorageAdapter` (browser). Server: `PostgresAdapter`, `RedisAdapter`.81Offline: `IndexedDBAdapter`. Hybrid: `HybridAdapter` (local + remote sync).82Custom: implement `{ getWatermark, setWatermark, getDismissedIds, addDismissedId }`.8384## Provider Props8586```tsx87<FeatureDropProvider88 manifest={features} // required89 storage={adapter} // required90 analytics={{ onFeatureSeen, onFeatureDismissed, onFeatureClicked }}91 userContext={{ plan, role, region }} // for audience targeting92 appVersion="2.1.0" // semver gating93 throttle={{ maxToastsPerSession: 3, modalCooldownMs: 120_000 }}94 locale="en" // i18n (en/es/fr/de/pt/zh-cn/ja/ko/ar/hi)95 animation="normal" // "none" | "subtle" | "normal" | "playful"96 engine={engineInstance} // optional: FeatureDropEngine for smart delivery97/>98```99100## Tailwind Integration101102```ts103// tailwind.config.ts104import { featureDropPlugin } from 'featuredrop/tailwind'105106export default {107 plugins: [featureDropPlugin({ prefix: 'fd' })],108}109// Adds: fd-badge, fd-badge-dot, fd-badge-count, fd-animate-pulse, fd-animate-fade-in110// CSS vars: --fd-new, --fd-changelog-bg, --fd-tour-bg (auto dark mode)111```112113## Rules114115- Always use subpath imports (`featuredrop/react`, not just `featuredrop`)116- Prefer hooks from `featuredrop/react/hooks` when the project uses shadcn, Radix, or custom design system117- Features auto-expire via `showNewUntil` — don't build manual expiry logic118- Zero production dependencies — don't add external deps119- TypeScript strict mode — no `any` types120- All components support headless mode via render props121- Core < 3 kB, React ~12 kB, fully tree-shakeable