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

config-driven-testimonials

v1.2.2

Published

Config-driven React testimonials widget — drop in your config, get a polished UI

Downloads

1,510

Readme

config-driven-testimonials

A polished React testimonials widget powered entirely by a single JSON config. No database. No API. No CMS. Avatars are embedded in the config as base64 — deploy it anywhere, instantly.

  • Zero infrastructure — your data lives in one .json file, not in a server
  • Truly portable — works on Vercel, GitHub Pages, S3, or any static host
  • Self-contained avatars — images are base64-encoded inside the config, no external storage needed
  • Configure once, reuse everywhere — drop in a new host app, point at the same config, done
  • Multiple display variantscards, carousel (3D fan, auto-advance, swipe), timeline, masonry
  • Accessible by default — WCAG 2.2 Level AAA compliant

npm license styles bundled WCAG 2.2 AAA Coverage Lighthouse


See it in action

▶ Live demo

▶ Try the visual editor — build your config in minutes, export JSON, drop it in


Getting started

1. Install

npm install config-driven-testimonials
# or
pnpm add config-driven-testimonials

React 18+ is a peer dependency. No Tailwind setup required — styles are bundled inside the component.

2. Use the widget

import { TestimonialsWidget, parseConfig } from 'config-driven-testimonials';
import configJson from './testimonials.config.json';

const config = parseConfig(configJson);

export function TestimonialsSection() {
  return <TestimonialsWidget config={config} />;
}

Create testimonials.config.json using the visual editor or write it by hand — see the Config reference below.


Props

| Prop | Type | Default | Description | |---|---|---|---| | config | TestimonialConfig | required | Validated config object | | classPrefix | string | 't' | Prefix for all CSS class names | | activeTestimonialId | string | — | Highlights one card (used by the editor preview) |


parseConfig

Use parseConfig when loading a JSON file to get runtime validation and correct TypeScript types:

import { parseConfig } from 'config-driven-testimonials';
import raw from './testimonials.config.json';

const config = parseConfig(raw); // throws with a descriptive message if invalid

Config reference

interface TestimonialConfig {
  author: Person;            // your profile — shown in the widget header
  testimonials: Testimonial[];
  theme?: ThemeConfig;
}

Person

interface Person {
  name?: string;
  title?: string;
  summary?: string;          // short bio rendered under title
  avatarUrl?: string;        // URL or base64 data URI
  linkedinUrl?: string;
  links?: { label: string; url: string }[];  // GitHub, portfolio, etc.
  currentRole?: { title: string; company: string };
}

Testimonial

interface Testimonial {
  id: string;
  author: Person;            // who wrote the recommendation
  text: string;
  relationship: string;      // e.g. "Managed Kostya at RBC"
  date: string;              // e.g. "March 2024"
  source: TestimonialSource;
  recommendationUrl?: string;
  associatedRole: {
    company: string;
    period: string;          // e.g. "2022 – 2024"
    type: 'employment' | 'contract' | 'education' | 'side-project';
    project?: string;
  };
  weight?: EndorsementWeight;
}

TestimonialSource

type TestimonialSource =
  | { type: 'linkedin'; url: string }
  | { type: 'reference-letter'; available: true }
  | { type: 'verbal'; contactAvailable?: boolean };

EndorsementWeight

Signals the seniority and context of the endorser. Rendered as a badge on the card.

interface EndorsementWeight {
  level: 'report' | 'mentee' | 'colleague' | 'lead' | 'manager' | 'director' | 'vp' | 'c-level';
  yearsExperience?: number;  // shown on badge hover
}

ThemeConfig

interface ThemeConfig {
  variant?: 'cards' | 'carousel' | 'timeline' | 'masonry';  // default: 'cards'
  colorScheme?: 'light' | 'dark' | 'auto';  // default: 'auto'
  accentColor?: string;         // CSS color value, e.g. '#6366f1'
  backgroundColor?: string;     // overrides the page background behind the widget
  showHeader?: boolean;         // default: true
  carouselInterval?: number;    // auto-advance interval in ms (1–60 000); default: 5000
  timeline?: {
    groupBy?: 'type' | 'company';
    include?: ('employment' | 'contract' | 'education' | 'side-project')[];
  };
}

Display variants

| Variant | Description | |---|---| | cards | Stacked cards with fade-in animation. Default. | | carousel | 3D fan layout. Active card is centred; adjacent cards are scaled and dimmed. Auto-advances every carouselInterval ms. Pause/play button included. Swipe on touch devices. | | timeline | Cards grouped by role type or company, ordered chronologically. | | masonry | Pinterest-style column layout. |


CSS class customization

Every rendered element receives a semantic class prefixed by classPrefix (default 't'): t-card, t-text, t-avatar, t-badge, etc. Override any of them in your stylesheet:

.t-card {
  border-radius: 16px;
}

Change the prefix to avoid conflicts:

<TestimonialsWidget config={config} classPrefix="my" />
/* renders: my-card, my-text, my-avatar … */

Related