Documentation

Everything you need to embed and customize the testimonials widget.

Quick Start

Add the widget to any HTML page in two lines:

<script src="https://astrowidgets.dev/widgets/testimonials.js"></script>

<testimonial-widget layout="grid" theme="light"></testimonial-widget>

That's it. The widget ships with demo data so you can see it working immediately. Replace the data with your own reviews using the data attribute, JS API, or hosted mode.

Hosted Mode

Instead of managing review data yourself, you can use the Astro Widgets dashboard to create widgets, configure their appearance, and manage reviews. Your widget loads its config and reviews automatically at runtime using a widget-id.

How it works

  1. Sign up for an account and create a widget in the dashboard.
  2. Configure layout, theme, and other settings visually.
  3. Add reviews manually (or connect review sources in a future update).
  4. Copy the embed code — it includes your widget-id.

Basic embed with meta tags

The simplest approach is to add Supabase config as <meta> tags on your page. All widgets on the page will use these automatically:

<!-- Add meta tags for Supabase config (once per page) -->
<meta name="supabase-url" content="https://your-project.supabase.co" />
<meta name="supabase-key" content="your-publishable-key" />

<script src="https://astrowidgets.dev/widgets/testimonials.js"></script>

<!-- The widget fetches its config and reviews automatically -->
<testimonial-widget widget-id="your-widget-uuid"></testimonial-widget>

Per-widget config override

You can also pass the Supabase URL and key directly on the widget element, which takes priority over meta tags:

<!-- Override Supabase config per widget (no meta tags needed) -->
<testimonial-widget
  widget-id="your-widget-uuid"
  supabase-url="https://your-project.supabase.co"
  supabase-key="your-publishable-key"
></testimonial-widget>

When a widget-id is present, the widget fetches its saved configuration (layout, theme, visibility toggles, custom CSS) and reviews from the backend. You can still override any attribute on the element — local attributes take priority over the stored config.

Note: The publishable key is safe to include in client-side code. It only allows read access to published widgets. Never expose your secret/service key.

HTML Attributes

Configure the widget entirely through HTML attributes:

Attribute Type Default Description
layout string "grid" Layout style: grid, slider, list, badge, masonry
theme string "light" Color theme: light or dark
columns number 3 Number of columns for grid and masonry layouts
max-reviews number 0 (all) Maximum number of reviews to display. 0 shows all.
show-rating boolean true Show star ratings
show-date boolean true Show review dates
show-source boolean true Show source badges (Google, Yelp, etc.)
show-avatar boolean true Show reviewer avatars or initials
autoplay boolean false Auto-rotate slides (slider layout only)
autoplay-speed number 5000 Autoplay interval in milliseconds
data string JSON string of review data (see Data Format)
custom-css string Raw CSS to inject into the shadow DOM
widget-id string UUID of a hosted widget. When set, the widget fetches its config and reviews from the backend. See Hosted Mode.
supabase-url string Supabase project URL. Overrides the <meta name="supabase-url"> tag. Only needed with widget-id.
supabase-key string Supabase publishable key. Overrides the <meta name="supabase-key"> tag. Only needed with widget-id.

Example with all options

<testimonial-widget
  layout="grid"
  theme="dark"
  columns="2"
  max-reviews="4"
  show-rating="true"
  show-date="false"
  show-source="true"
  show-avatar="true"
  autoplay="false"
></testimonial-widget>

CSS Custom Properties

Override the widget's appearance without touching its internals. Set these properties on the <testimonial-widget> element:

Property Default (Light) Description
--tw-bgtransparentWidget background
--tw-card-bg#ffffffCard background color
--tw-card-bg-hover#fafafaCard background on hover
--tw-text#1a1a2ePrimary text color
--tw-text-secondary#64648cSecondary text (dates, source names)
--tw-accent#6c5ce7Accent color (dots, highlights)
--tw-star-color#f59e0bFilled star color
--tw-star-empty#d1d5dbEmpty star color
--tw-border-color#e5e7ebBorder color
--tw-border-radius12pxCard border radius
--tw-card-shadowsubtleCard box shadow
--tw-card-shadow-hoverelevatedCard shadow on hover
--tw-card-padding24pxCard internal padding
--tw-card-border1px solid ...Card border shorthand
--tw-font-familysystem fontsFont family
--tw-font-size15pxReview text size
--tw-font-size-name15pxReviewer name size
--tw-font-size-small13pxSmall text size (dates, sources)
--tw-avatar-size44pxAvatar diameter
--tw-gap20pxGap between cards
--tw-max-width1200pxMaximum widget width
--tw-transition0.25s easeTransition timing
--tw-quote-font-stylenormalQuote text font style (try italic)

Example: Custom brand colors

<testimonial-widget
  layout="grid"
  style="
    --tw-accent: #e74c3c;
    --tw-star-color: #e74c3c;
    --tw-card-bg: #fef9f8;
    --tw-border-radius: 20px;
    --tw-font-family: Georgia, serif;
  "
></testimonial-widget>

Custom CSS Injection

For complete control, inject arbitrary CSS into the widget's shadow DOM using the custom-css attribute:

<testimonial-widget
  layout="grid"
  custom-css=".tw-card { border: 2px solid #e74c3c; } .tw-name { color: #e74c3c; }"
></testimonial-widget>

Available internal class names

ClassElement
.tw-rootRoot container
.tw-cardReview card
.tw-card-headerCard header (avatar + meta)
.tw-avatarAvatar image/initials
.tw-nameReviewer name
.tw-starsStar rating container
.tw-dateReview date
.tw-textReview text (blockquote)
.tw-sourceSource badge
.tw-card-footerCard footer

JavaScript API

Programmatically control the widget after it's rendered:

// Get the widget element
const widget = document.querySelector('testimonial-widget');

// Set reviews programmatically
widget.setReviews([
  {
    name: 'Jane Doe',
    avatar: 'https://example.com/avatar.jpg',
    rating: 5,
    text: 'Amazing product!',
    date: '2026-03-01',
    source: 'google'
  }
]);

// Or use the reviews property
widget.reviews = myReviewsArray;

// Change attributes dynamically
widget.setAttribute('layout', 'slider');
widget.setAttribute('theme', 'dark');

Data Format

Each review object accepts these fields:

{
  "name": "Sarah Chen",        // Required. Reviewer name.
  "avatar": "",                // Optional. URL to avatar image.
                               // If empty, initials are shown.
  "rating": 5,                 // Required. 1-5 star rating.
  "text": "Great service!",    // Required. Review text.
  "date": "2026-02-18",       // Optional. ISO date string.
  "source": "google"           // Optional. One of: google, yelp,
                               //   facebook, trustpilot
}

Via HTML attribute

Pass reviews as a JSON string in the data attribute:

<testimonial-widget
  layout="grid"
  data='[{"name":"Jane","rating":5,"text":"Wonderful!","source":"google"}]'
></testimonial-widget>

Astro Integration

In an Astro project, add the script and use the component directly in your .astro files:

---
// src/pages/index.astro
import Layout from '../layouts/Layout.astro';

const reviews = await fetch('/api/reviews').then(r => r.json());
---
<Layout>
  <script src="/widgets/testimonials.js" is:inline></script>

  <testimonial-widget
    layout="masonry"
    columns="3"
    theme="light"
    data={JSON.stringify(reviews)}
  ></testimonial-widget>
</Layout>

You can also host the widget JS in your own public/ directory instead of loading it from our CDN.

Dynamic island pattern

For dynamic review loading, use a client-side script:

<testimonial-widget id="reviews" layout="grid"></testimonial-widget>

<script is:inline>
  fetch('/api/reviews')
    .then(r => r.json())
    .then(data => {
      document.getElementById('reviews').setReviews(data);
    });
</script>