0.0.7 • Published 8 months ago
@feedal/embed v0.0.7
🚀 Feedal Embed SDK v2.0
A powerful, modern, and flexible JavaScript SDK for embedding Feedal feedback forms across any platform. Built with TypeScript, featuring advanced customization, multiple display modes, framework integration, and excellent developer experience.
✨ Key Features
- 🎯 Framework Agnostic: Works with React, Angular, Vue, Svelte, and vanilla JavaScript
- 🎨 Multiple Display Modes: Popup, embedded, fullscreen, drawer, and floating button
- 🎭 Smart Triggers: Manual, auto, click, scroll, time-based, and element-specific
- 📱 Fully Responsive: Mobile-first design with adaptive positioning
- 🎬 Smooth Animations: Fade, slide, scale transitions with customizable timing
- ♿ Accessibility First: ARIA labels, keyboard navigation, screen reader support
- 🔧 Advanced Configuration: Extensive customization options
- 📦 Lightweight: ~15KB gzipped, no dependencies
- 🔒 Secure: Token-based authentication with HMAC support
- 🌐 Web Components: Native custom elements support
📦 Installation
CDN (Recommended for quick setup)
<script src="https://cdn.jsdelivr.net/npm/@feedal/embed@latest/dist/embed.umd.js"></script>NPM/Yarn (Recommended for applications)
npm install @feedal/embed
# or
yarn add @feedal/embed🚀 Quick Start
Simple Popup Form
<script src="https://cdn.jsdelivr.net/npm/@feedal/embed@latest/dist/embed.umd.js"></script>
<script>
const widget = FeedalForm.createWidget({
formId: 'your-form-id',
token: 'your-auth-token',
mode: 'popup'
});
widget.open();
</script>Auto-trigger with Script Tag
<script
src="https://cdn.jsdelivr.net/npm/@feedal/embed@latest/dist/embed.umd.js"
data-form-id="your-form-id"
data-token="your-auth-token"
data-mode="popup"
data-trigger="time"
data-trigger-delay="5000"
data-position="bottom-right"
data-animation="slide">
</script>🎛️ Complete Configuration Options
interface EmbedOptions {
// Core Configuration
formId: string; // Required: Your form ID
token?: string; // Authentication token
host?: string; // API host (defaults to production)
// Display & Layout
mode?: 'fullscreen' | 'embedded' | 'popup' | 'drawer' | 'button';
theme?: 'light' | 'dark' | 'auto' | 'custom';
customCssUrl?: string; // Custom CSS file URL
// Positioning & Sizing
width?: string | number; // Default: '400px'
height?: string | number; // Default: '600px'
position?: 'top-left' | 'top-center' | 'top-right' |
'bottom-left' | 'bottom-center' | 'bottom-right' | 'center';
offset?: { x?: number; y?: number }; // Fine-tune positioning
// Behavior
trigger?: 'manual' | 'auto' | 'click' | 'scroll' | 'time';
triggerDelay?: number; // Delay for time/auto triggers
triggerElement?: string | HTMLElement; // Target element for click trigger
autoClose?: boolean | number; // Auto-close after submission
closeOnOverlayClick?: boolean; // Close when clicking outside
showCloseButton?: boolean; // Show/hide close button
// Responsive & Accessibility
responsive?: boolean; // Enable responsive behavior
maxWidth?: string | number; // Maximum width constraint
minWidth?: string | number; // Minimum width constraint
zIndex?: number; // Custom z-index
ariaLabel?: string; // Accessibility label
// Advanced Features
containerId?: string; // Container for embedded mode
animation?: 'fade' | 'slide' | 'scale' | 'none';
overlay?: boolean; // Show background overlay
// Data & Context
metadata?: Record<string, any>; // Additional context data
prefill?: Record<string, any>; // Prefill form fields
// Event Callbacks
onLoad?: () => void; // Form loaded and ready
onOpen?: () => void; // Form opened/shown
onClose?: () => void; // Form closed/hidden
onSubmit?: (data?: any) => void; // Form submitted
onError?: (error: Error) => void; // Error occurred
}🎮 Display Modes
1. Popup Mode (Default)
Displays form in a centered modal overlay.
FeedalForm.createWidget({
formId: 'abc123',
mode: 'popup',
position: 'center',
width: 500,
height: 700,
overlay: true,
animation: 'fade'
});2. Embedded Mode
Embeds form inside a specific container.
<div id="feedback-container"></div>
<script>
FeedalForm.createWidget({
formId: 'abc123',
mode: 'embedded',
containerId: 'feedback-container',
width: '100%',
height: 600
});
</script>3. Drawer Mode
Slides in from the side of the screen.
FeedalForm.createWidget({
formId: 'abc123',
mode: 'drawer',
position: 'bottom-right',
width: 400,
animation: 'slide'
});4. Floating Button
Shows a floating button that expands to form.
FeedalForm.createWidget({
formId: 'abc123',
mode: 'button',
position: 'bottom-right',
trigger: 'manual'
});🎯 Smart Triggers
Manual Trigger
const widget = FeedalForm.createWidget({
formId: 'abc123',
trigger: 'manual'
});
// Open programmatically
widget.open();Time-based Trigger
FeedalForm.createWidget({
formId: 'abc123',
trigger: 'time',
triggerDelay: 10000 // 10 seconds
});Scroll Trigger
FeedalForm.createWidget({
formId: 'abc123',
trigger: 'scroll',
triggerDelay: 75 // Trigger at 75% scroll
});Click Trigger
FeedalForm.createWidget({
formId: 'abc123',
trigger: 'click',
triggerElement: '#feedback-button' // CSS selector or HTML element
});🌐 Framework Integration
React
import { FeedalWidget, EmbedOptions } from '@feedal/embed';
import { useEffect, useState } from 'react';
function FeedbackForm({ formId, ...options }: EmbedOptions) {
const [widget, setWidget] = useState<FeedalWidget | null>(null);
useEffect(() => {
const feedalWidget = new FeedalWidget({
formId,
...options,
onSubmit: (data) => {
console.log('Form submitted:', data);
}
});
setWidget(feedalWidget);
return () => feedalWidget.destroy();
}, [formId]);
return (
<button onClick={() => widget?.open()}>
Give Feedback
</button>
);
}Vue 3
<template>
<button @click="widget?.open()">Give Feedback</button>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { FeedalWidget, EmbedOptions } from '@feedal/embed';
interface Props extends EmbedOptions {
formId: string;
}
const props = defineProps<Props>();
const widget = ref<FeedalWidget | null>(null);
onMounted(() => {
widget.value = new FeedalWidget(props);
});
onUnmounted(() => {
widget.value?.destroy();
});
</script>Angular
import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { FeedalWidget, EmbedOptions } from '@feedal/embed';
@Component({
selector: 'app-feedback',
template: `<button (click)="openFeedback()">Give Feedback</button>`
})
export class FeedbackComponent implements OnInit, OnDestroy {
@Input() formId!: string;
@Input() options: Partial<EmbedOptions> = {};
private widget?: FeedalWidget;
ngOnInit() {
this.widget = new FeedalWidget({
formId: this.formId,
...this.options
});
}
ngOnDestroy() {
this.widget?.destroy();
}
openFeedback() {
this.widget?.open();
}
}Web Components
<feedal-form
form-id="abc123"
token="your-token"
mode="popup"
theme="dark"
auto-close="true">
</feedal-form>
<script>
const form = document.querySelector('feedal-form');
form.addEventListener('submit', (event) => {
console.log('Form submitted:', event.detail);
});
</script>🎨 Advanced Customization
Custom Themes
FeedalForm.createWidget({
formId: 'abc123',
theme: 'custom',
customCssUrl: 'https://yoursite.com/feedal-theme.css'
});Custom CSS Variables
:root {
--feedal-primary-color: #6366f1;
--feedal-background: #ffffff;
--feedal-text-color: #374151;
--feedal-border-radius: 12px;
--feedal-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}Dynamic Configuration
const widget = FeedalForm.createWidget({
formId: 'abc123',
mode: 'popup'
});
// Update configuration dynamically
widget.updateOptions({
theme: 'dark',
position: 'bottom-right',
width: 600
});📱 Responsive Design
The SDK automatically adapts to different screen sizes:
- Desktop: Full-sized popups and drawers
- Tablet: Responsive sizing with max-width constraints
- Mobile: Full-width modals with optimized positioning
FeedalForm.createWidget({
formId: 'abc123',
responsive: true,
width: 500,
maxWidth: '90vw', // Ensures mobile compatibility
minWidth: 320
});🔐 Authentication & Security
JWT Tokens
FeedalForm.createWidget({
formId: 'abc123',
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
metadata: {
userId: '12345',
userEmail: 'user@example.com'
}
});HMAC Signatures
const signature = generateHMACSignature(formId, timestamp, secretKey);
FeedalForm.createWidget({
formId: 'abc123',
token: signature,
metadata: { timestamp }
});📊 Event Handling & Analytics
const widget = FeedalForm.createWidget({
formId: 'abc123',
onLoad: () => {
console.log('Form loaded');
analytics.track('Feedback Form Loaded');
},
onOpen: () => {
console.log('Form opened');
analytics.track('Feedback Form Opened');
},
onSubmit: (data) => {
console.log('Form submitted:', data);
analytics.track('Feedback Submitted', data);
},
onClose: () => {
console.log('Form closed');
analytics.track('Feedback Form Closed');
},
onError: (error) => {
console.error('Form error:', error);
analytics.track('Feedback Form Error', { error: error.message });
}
});🛠️ Advanced API
Widget Management
// Create multiple widgets
const feedbackWidget = FeedalForm.createWidget({ formId: 'feedback-123' });
const surveyWidget = FeedalForm.createWidget({ formId: 'survey-456' });
// Access widgets by ID
const widget = FeedalForm.getInstance('feedback-123');
// Destroy specific widget
widget.destroy();
// Destroy all widgets
FeedalForm.destroyAll();
// Check if any widget is open
if (FeedalForm.isFormOpen()) {
console.log('A form is currently open');
}Programmatic Control
const widget = FeedalForm.createWidget({
formId: 'abc123',
trigger: 'manual'
});
// Open/close/toggle
widget.open();
widget.close();
widget.toggle();
// Check state
console.log(widget.isVisible); // boolean
console.log(widget.element); // HTMLElement | null
// Update options
widget.updateOptions({
theme: 'dark',
position: 'top-right'
});🔧 Migration Guide
From v1.x to v2.x
// Old API (v1.x) - Still supported
openForm('abc123', {
theme: 'dark',
mode: 'popup'
});
// New API (v2.x) - Recommended
const widget = FeedalForm.createWidget({
formId: 'abc123',
theme: 'dark',
mode: 'popup'
});
widget.open();Breaking Changes
popovermode renamed topopuppopoverPositionrenamed topositioncustomCssUrlreplaces individual CSS parameters- Enhanced TypeScript definitions
🐛 Troubleshooting
Common Issues
Form not loading:
// Check console for errors
widget.onError = (error) => console.error(error);
// Verify form ID and token
console.log('Form ID:', widget.options.formId);Styling conflicts:
/* Isolate Feedal styles */
#feedal-widget-abc123 {
all: initial;
}Mobile issues:
// Enable responsive mode
FeedalForm.createWidget({
formId: 'abc123',
responsive: true,
width: '90vw',
maxWidth: 500
});📈 Performance Tips
- Lazy Loading: Load the SDK only when needed
- Preload: Use
<link rel="preload">for critical forms - Caching: Enable CDN caching for better performance
- Minimize: Use production builds in production
// Lazy load example
async function loadFeedbackForm() {
if (!window.FeedalForm) {
await import('@feedal/embed');
}
return FeedalForm.createWidget({
formId: 'abc123'
});
}🆘 Support & Resources
- 📖 Documentation: docs.feedal.io
- 💬 Support: support@feedal.io
- 🐛 Issues: GitHub Issues
- 💡 Feature Requests: GitHub Discussions
📄 License
This project is licensed under the MIT License.
Made with ❤️ by the Feedal Team