INTEGRATIONS

React + Shoutjar

Add testimonial components to your React app. NPM package with TypeScript support. Or just drop in a script tag.

Works with CRA, Vite, Parcel
TypeScript support
Zero dependencies
React
Shoutjar

Method 1: NPM Package

The recommended way to add Shoutjar to React. Full TypeScript support and tree-shakeable.

Install

Terminal
npm install @shoutjar/react
# or
yarn add @shoutjar/react
# or
pnpm add @shoutjar/react

Basic Usage

App.tsx
import { ShoutjarWidget } from '@shoutjar/react'

function App() {
  return (
    <div>
      <h1>My App</h1>
      <ShoutjarWidget widgetId="YOUR_WIDGET_ID" />
    </div>
  )
}

export default App

With Configuration

Testimonials.tsx
import { ShoutjarWidget } from '@shoutjar/react'

function Testimonials() {
  return (
    <ShoutjarWidget
      widgetId="YOUR_WIDGET_ID"
      style="carousel"
      theme="dark"
      maxItems={6}
      showRating={true}
      showSource={true}
      className="my-4"
    />
  )
}

Available Widget Styles

Widget Styles
// Grid - Multiple testimonials in columns
<ShoutjarWidget widgetId="..." style="grid" />

// Carousel - One at a time, auto-rotate
<ShoutjarWidget widgetId="..." style="carousel" />

// Marquee - Continuous scrolling ticker
<ShoutjarWidget widgetId="..." style="marquee" />

// Badge - Compact rating display
<ShoutjarWidget widgetId="..." style="badge" />

// Single - Feature one testimonial
<ShoutjarWidget widgetId="..." style="single" />

Method 2: Script Tag

For simple setups or quick testing. No build step required.

Add Script to HTML

index.html
<!-- In your index.html -->
<script src="https://cdn.shoutjar.com/widget.js" defer></script>

Use in React Component

Testimonials.tsx
function Testimonials() {
  return (
    <div
      data-shoutjar-widget="YOUR_WIDGET_ID"
      data-shoutjar-style="carousel"
    />
  )
}

Or Create a Wrapper Component

ShoutjarEmbed.tsx
import { useEffect, useRef } from 'react'

function ShoutjarEmbed({ widgetId, style = 'carousel' }) {
  const ref = useRef<HTMLDivElement>(null)

  useEffect(() => {
    if (window.Shoutjar && ref.current) {
      window.Shoutjar.init(ref.current)
    }
  }, [widgetId])

  return (
    <div
      ref={ref}
      data-shoutjar-widget={widgetId}
      data-shoutjar-style={style}
    />
  )
}

The NPM package is recommended for production apps. The script tag works but lacks TypeScript support and tree-shaking.

TypeScript

Full TypeScript definitions included. No @types packages needed.

Component Props

types.d.ts
import { ShoutjarWidget } from '@shoutjar/react'
import type { WidgetProps, WidgetStyle, WidgetTheme } from '@shoutjar/react'

type WidgetStyle = 'grid' | 'carousel' | 'marquee' | 'badge' | 'single'
type WidgetTheme = 'light' | 'dark' | 'auto'

interface WidgetProps {
  widgetId: string
  style?: WidgetStyle
  theme?: WidgetTheme
  maxItems?: number
  showRating?: boolean
  showSource?: boolean
  className?: string
  onLoad?: () => void
  onError?: (error: Error) => void
}

Usage with Types

Testimonials.tsx
import { ShoutjarWidget, WidgetStyle } from '@shoutjar/react'

interface Props {
  testimonialStyle: WidgetStyle
}

function Testimonials({ testimonialStyle }: Props) {
  return (
    <ShoutjarWidget
      widgetId={import.meta.env.VITE_SHOUTJAR_WIDGET_ID}
      style={testimonialStyle}
    />
  )
}

Works With Your Setup

Same NPM package, same component. Just different environment variable prefixes.

C
Create React App (CRA)

src/App.tsx
import { ShoutjarWidget } from '@shoutjar/react'

function App() {
  return (
    <div className="App">
      <ShoutjarWidget
        widgetId={process.env.REACT_APP_SHOUTJAR_WIDGET_ID!}
      />
    </div>
  )
}
.env
REACT_APP_SHOUTJAR_WIDGET_ID=your_widget_id

V
Vite

src/App.tsx
import { ShoutjarWidget } from '@shoutjar/react'

function App() {
  return (
    <ShoutjarWidget
      widgetId={import.meta.env.VITE_SHOUTJAR_WIDGET_ID}
    />
  )
}
.env
VITE_SHOUTJAR_WIDGET_ID=your_widget_id

G
Gatsby

src/pages/index.tsx
import { ShoutjarWidget } from '@shoutjar/react'

export default function Page() {
  return (
    <ShoutjarWidget
      widgetId={process.env.GATSBY_SHOUTJAR_WIDGET_ID}
    />
  )
}

Parcel

Same as Vite -- environment variables work with PARCEL_ prefix.

For Next.js, see our dedicated Next.js integration guide -- it covers App Router, Pages Router, SSR, and dynamic imports.

Common Usage Patterns

Hero Section Social Proof

function Hero() {
  return (
    <section className="hero">
      <h1>Your Product</h1>
      <p>Value proposition here</p>
      <button>Get Started</button>
      <ShoutjarWidget
        widgetId="YOUR_WIDGET_ID"
        style="badge"
        className="mt-4"
      />
    </section>
  )
}

Dedicated Testimonials Section

function TestimonialsSection() {
  return (
    <section className="py-16 bg-gray-50">
      <div className="max-w-6xl mx-auto">
        <h2 className="text-3xl font-bold text-center mb-8">
          What Our Customers Say
        </h2>
        <ShoutjarWidget
          widgetId="YOUR_WIDGET_ID"
          style="grid"
          maxItems={6}
        />
      </div>
    </section>
  )
}

Footer Trust Bar

function Footer() {
  return (
    <footer>
      <ShoutjarWidget
        widgetId="YOUR_WIDGET_ID"
        style="marquee"
        className="border-t border-b py-4"
      />
      <div className="py-8">{/* Footer links */}</div>
    </footer>
  )
}

Conditional Rendering

function Testimonials({ isVisible = true }) {
  if (!isVisible) return null

  return (
    <ShoutjarWidget
      widgetId="YOUR_WIDGET_ID"
      onLoad={() => console.log('Widget loaded')}
      onError={(err) => console.error('Widget error:', err)}
    />
  )
}

Multiple Widgets

function App() {
  return (
    <>
      <header>
        <ShoutjarWidget widgetId="badge_widget_id" style="badge" />
      </header>
      <main>
        <ShoutjarWidget widgetId="grid_widget_id" style="grid" />
      </main>
      <footer>
        <ShoutjarWidget widgetId="marquee_widget_id" style="marquee" />
      </footer>
    </>
  )
}

Customization & Styling

CSS Classes

className prop
<ShoutjarWidget
  widgetId="YOUR_WIDGET_ID"
  className="rounded-lg shadow-lg border"
/>

CSS Variables

index.css
:root {
  --shoutjar-primary: #3B82F6;
  --shoutjar-background: #ffffff;
  --shoutjar-text: #111827;
  --shoutjar-text-secondary: #6B7280;
  --shoutjar-border: #E5E7EB;
  --shoutjar-radius: 8px;
}

.dark {
  --shoutjar-background: #1F2937;
  --shoutjar-text: #F9FAFB;
  --shoutjar-text-secondary: #9CA3AF;
  --shoutjar-border: #374151;
}

Tailwind CSS

Testimonials.tsx
<ShoutjarWidget
  widgetId="YOUR_WIDGET_ID"
  className="max-w-4xl mx-auto p-4 bg-white dark:bg-gray-800 rounded-xl shadow-md"
/>

Styled Components

Testimonials.tsx
import styled from 'styled-components'
import { ShoutjarWidget } from '@shoutjar/react'

const StyledWrapper = styled.div`
  background: linear-gradient(to bottom, #f9fafb, #ffffff);
  padding: 2rem;
  border-radius: 1rem;
`

function Testimonials() {
  return (
    <StyledWrapper>
      <ShoutjarWidget widgetId="YOUR_WIDGET_ID" />
    </StyledWrapper>
  )
}

Configuration Options

Widget Props

PropTypeDefaultDescription
widgetIdstringrequiredYour Shoutjar widget ID
stylestring'carousel'Widget style: grid, carousel, marquee, badge, single
themestring'auto'Color theme: light, dark, auto
maxItemsnumberundefinedMaximum testimonials to show
showRatingbooleantrueShow star ratings
showSourcebooleantrueShow source icons (Twitter, G2, etc.)
classNamestringundefinedCustom CSS class
onLoad() => voidundefinedCallback when widget loads
onError(error: Error) => voidundefinedCallback on error

Performance

~3KB

gzipped bundle

Zero

dependencies

Yes

tree-shakeable

Lazy Loading

Testimonials.tsx
import { lazy, Suspense } from 'react'

const ShoutjarWidget = lazy(() =>
  import('@shoutjar/react').then(mod => ({ default: mod.ShoutjarWidget }))
)

function Testimonials() {
  return (
    <Suspense fallback={<div>Loading testimonials...</div>}>
      <ShoutjarWidget widgetId="YOUR_WIDGET_ID" />
    </Suspense>
  )
}

Best Practices

1

One widget ID per style -- don't reuse the same widget with different styles

2

Lazy load widgets below the fold

3

Use environment variables -- don't hardcode widget IDs

4

Let widgets handle responsiveness -- don't constrain width unnecessarily

Where Testimonials Come From

Shoutjar pulls in reviews from multiple platforms into one unified widget

Social Media

  • Twitter/X
  • LinkedIn
  • Reddit
  • Hacker News

Manual Entry

  • API or dashboard
  • Add testimonials programmatically
  • Or enter them manually

Auto-Discovery

Shoutjar monitors mentions of your product across the web -- even untagged tweets and Reddit threads.

All sources display in one unified widget -- no multiple integrations needed.

Frequently Asked Questions

Does it work with Create React App?

Yes. Install the NPM package and use it like any React component.

Does it work with Vite?

Yes. Same as CRA -- install and import the component.

Is TypeScript supported?

Yes. Full type definitions included in the package.

What's the bundle size?

~3KB gzipped. Zero dependencies (React is a peer dependency).

Can I use it with SSR frameworks?

Yes. For Next.js, see our dedicated Next.js guide. For other SSR frameworks, the component renders client-side.

Can I style the widgets?

Yes. Use className prop, CSS variables, or configure in Shoutjar dashboard.

How do I update testimonials?

Add or edit testimonials in Shoutjar. Changes appear in your app automatically -- no code changes needed.

Can I have multiple widgets on one page?

Yes. Each can have different styles and configurations.

Works With Other Platforms Too

Use Shoutjar anywhere you build

Add Testimonials to Your React App

NPM package with TypeScript support. Works with CRA, Vite, and any React setup. Start in 5 minutes.

TypeScript support
~3KB gzipped
Free plan available