Skip to content

open-loopback/loopback

Repository files navigation

open-loopback

Beautiful, embeddable feedback widget for React.

open-loopback is a polished, themeable feedback component you can drop into any React app.
It supports modal and embedded layouts, emoji/star/number ratings, rich theming (including dark mode), and both controlled and uncontrolled usage.


Installation

npm install open-loopback
# or
yarn add open-loopback
# or
pnpm add open-loopback

Peer dependencies

Make sure your project has:

  • react ≥ 16.8.0
  • react-dom ≥ 16.8.0

Quick Start

Modal widget (uncontrolled)

import React from "react";
import { Loopback } from "open-loopback";
import "open-loopback/style.css"; // include styles

export function App() {
  return (
    <div>
      <h1>My App</h1>
      <Loopback
        sourceId="my-product"
        variant="modal"
        position="bottom-right"
        defaultOpen={false}
      />
    </div>
  );
}

Embedded widget (inline card)

import React from "react";
import { Loopback } from "open-loopback";
import "open-loopback/style.css";

export function FeedbackSection() {
  return (
    <section style={{ maxWidth: 420, margin: "0 auto", padding: 24 }}>
      <Loopback
        sourceId="docs-section"
        variant="embedded"
        ratingType="emoji"
        content={{
          title: "How helpful was this page?",
          subtitle: "Your feedback helps us improve.",
        }}
      />
    </section>
  );
}

Component Overview

The main export is:

  • Loopback – the feedback UI component
  • LoopbackProps – TypeScript props interface (re-exported)

You'll typically import it like:

import { Loopback } from "open-loopback";

…and once at app entry:

import "open-loopback/style.css";

Props

LoopbackProps

  • sourceId (string, required)
    Unique identifier for the feedback source (e.g. "homepage-hero", "pricing-page", "docs-search").

  • variant ("modal" | "embedded")

    • "modal": Floating trigger button + overlay card.
    • "embedded": Renders the card inline where you place the component.
    • Default: "modal".
  • position ("bottom-right" | "bottom-left" | "center")
    Position of the modal trigger/overlay.
    Default: "bottom-right".

  • ratingType ("emoji" | "star" | "number")
    How the rating scale is displayed.
    Default: "emoji".

  • ratingItems (LoopbackRatingItem[])
    Custom rating items if you want your own scale.

    Each LoopbackRatingItem is:

    • value (number)
    • label (ReactNode)

    If omitted, the widget uses:

    • Emojis 😭 → 🤩 for "emoji",
    • 1–5 numeric scale for "star" / "number".
  • isOpen (boolean)
    Control prop for the modal’s open state.
    When set, the component becomes controlled – you must handle open/close state yourself and respond to onClose.

  • defaultOpen (boolean)
    Initial open state for uncontrolled modal usage.
    Default: false.

  • onClose (() => void)
    Called when the widget should close (close button or after a successful submit).
    Use this to toggle your own isOpen state when in controlled mode.

  • showTrigger (boolean)
    Show the floating trigger button for variant="modal" in uncontrolled mode.

    • Set to false if you want to render your own button and control isOpen manually.
    • Default: true.
  • triggerAriaLabel (string)
    Accessible label for the trigger button.
    Default: "Open feedback".

  • theme (LoopbackTheme)
    Theming options (see Theming below).

  • content (LoopbackContent)
    Custom copy and labels, e.g. headings, helper text, button labels.

  • metadata (Record<string, unknown>)
    Optional custom data to send along with the feedback. Automatically merged with default metadata (url, referrer).

Prop Type Default Description
cardStyle CSSProperties - Optional inline styles for the main widget card.
triggerStyle CSSProperties - Optional inline styles for the floating trigger button.
submitButtonStyle CSSProperties - Optional inline styles for the submit button.
ratingButtonStyle CSSProperties - Optional inline styles for the rating buttons.
headerStyle CSSProperties - Optional inline styles for the header container.
textareaStyle CSSProperties - Optional inline styles for the textarea.
metadata Record<string, unknown> - Custom data payload for submissions.

Key Features

  • Character Limit: Feedback text is capped at 1000 characters. A counter is provided to guide the user.
  • Automatic Metadata: By default, the widget captures page context:
    • url (current window location)
    • referrer (originating page)
  • Error Handling: Graceful error states and retry UI for failed submissions.

Theming

We use standard CSS variables for styling. You can override these in your global CSS or via the theme prop.

The library automatically derives hover colors (darkening by 10% for primary, 5% for accent) using color-mix. You can override this behavior by setting --lb-primary-hover or --lb-accent-hover explicitly.

<Loopback
  theme={{
    primaryColor: "#E11D48", // Rose-600
    backgroundColor: "#ffffff",
    textColor: "#0f172a",
    starColor: "#cbd5e1", // Optional: customize inactive star color
    starActiveColor: "#fbbf24", // Optional: customize active star color
  }}
/>

Exported Types

We export several types to help with TypeScript development:

  • LoopbackProps
  • LoopbackTheme
  • FeedbackPosition
  • FeedbackRatingType
  • LoopbackRatingItem
  • LoopbackContent

LoopbackTheme

  • primaryColor? (string) – Accent color (buttons, active states).
  • backgroundColor? (string) – Card background.
  • textColor? (string) – Primary text color.
  • accentColor? (string) – Subtle accent background.
  • borderColor? (string) – Card + input border color.
  • borderRadius? (string) – Radius for the card and elements.
  • fontFamily? (string) – Custom font stack.
  • darkMode? (boolean) – Opt into a dark-friendly style; fills in sensible dark defaults.
  • zIndex? (number) – Stack order for modal overlay and trigger.

Example

<Loopback
  sourceId="checkout"
  variant="modal"
  position="center"
  ratingType="star"
  theme={{
    primaryColor: "#f97316",
    backgroundColor: "#020617",
    textColor: "#e5e7eb",
    darkMode: true,
    borderRadius: "16px",
    zIndex: 9999,
  }}
/>

Under the hood, the widget maps these values to CSS variables like:

  • --lb-primary
  • --lb-bg
  • --lb-text
  • --lb-border
  • --lb-font-family
  • --lb-z-index
  • etc.

You can further customize styling in your own CSS by targeting:

  • .lb-root
  • .lb-widget-overlay
  • .lb-widget-trigger
  • .lb-widget-card
  • .lb-textarea
  • .lb-submit-btn

Controlled vs Uncontrolled

You can let the widget manage its own open/close state or wire it to your own UI.

Uncontrolled (simplest)

<Loopback
  sourceId="homepage"
  variant="modal"
  defaultOpen={false}
  showTrigger={true}
/>

The widget:

  • Draws its own trigger button.
  • Handles open/close internally.

Controlled (custom trigger)

import React from "react";
import { Loopback } from "open-loopback";
import "open-loopback/style.css";

export function ControlledExample() {
  const [open, setOpen] = React.useState(false);

  return (
    <>
      <button onClick={() => setOpen(true)}>Give feedback</button>

      <Loopback
        sourceId="pricing"
        variant="modal"
        isOpen={open}
        onClose={() => setOpen(false)}
        showTrigger={false} // hide built-in trigger
      />
    </>
  );
}

License

MIT

You’re free to use, modify, and embed open-loopback in your own projects.

About

Beautiful, embeddable feedback widget for React.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •