angular-calendly
v1.0.0
Published
Angular library for integrating Calendly scheduling widgets
Downloads
21
Maintainers
Readme
Angular Calendly
Seamlessly integrate Calendly scheduling widgets into your Angular applications
A modern Angular library that provides standalone components for embedding Calendly scheduling widgets. Built with TypeScript, fully typed, and compatible with Angular 18+.
Table of Contents
- Features
- Installation
- Quick Start
- Usage
- API Reference
- Advanced Usage
- Examples
- SSR Support
- Troubleshooting
- Contributing
- License
Features
✨ Modern Angular - Standalone components compatible with Angular 18, 19, and 20
📱 Multiple Widget Types - Inline and Popup widgets for different use cases
🎨 Highly Customizable - Colors, prefill data, UTM parameters, and more
📊 Event Tracking - Built-in callbacks for user interactions
🔧 TypeScript First - Fully typed with comprehensive type definitions
🌐 SSR Compatible - Works seamlessly with Angular Universal
⚡ Zero Configuration - Automatic script loading and management
🪶 Lightweight - Minimal bundle impact with tree-shakable exports
Installation
Install via npm:
npm install angular-calendlyOr using yarn:
yarn add angular-calendlyOr using pnpm:
pnpm add angular-calendlyQuick Start
1. Import the Component
import { Component } from '@angular/core';
import { CalendlyInlineComponent } from 'angular-calendly';
@Component({
selector: 'app-booking',
standalone: true,
imports: [CalendlyInlineComponent],
template: `
<ng-calendly-inline
[url]="'https://calendly.com/your-username/30min'"
></ng-calendly-inline>
`
})
export class BookingComponent {}2. That's it!
The component automatically loads the Calendly SDK and renders the widget. No additional configuration needed.
Usage
Inline Widget
Embed Calendly directly into your page for a seamless booking experience.
Basic Example:
import { Component } from '@angular/core';
import { CalendlyInlineComponent } from 'angular-calendly';
@Component({
selector: 'app-scheduling',
standalone: true,
imports: [CalendlyInlineComponent],
template: `
<ng-calendly-inline
[url]="calendlyUrl"
[height]="700"
></ng-calendly-inline>
`
})
export class SchedulingComponent {
calendlyUrl = 'https://calendly.com/your-username/30min';
}With Prefill Data:
import { Component } from '@angular/core';
import { CalendlyInlineComponent, CalendlyPrefill } from 'angular-calendly';
@Component({
selector: 'app-scheduling',
standalone: true,
imports: [CalendlyInlineComponent],
template: `
<ng-calendly-inline
[url]="calendlyUrl"
[prefill]="prefillData"
[height]="700"
></ng-calendly-inline>
`
})
export class SchedulingComponent {
calendlyUrl = 'https://calendly.com/your-username/30min';
prefillData: CalendlyPrefill = {
name: 'John Doe',
email: '[email protected]',
firstName: 'John',
lastName: 'Doe'
};
}With Event Tracking:
import { Component } from '@angular/core';
import { CalendlyInlineComponent, CalendlyEvent } from 'angular-calendly';
@Component({
selector: 'app-scheduling',
standalone: true,
imports: [CalendlyInlineComponent],
template: `
<ng-calendly-inline
[url]="calendlyUrl"
(eventScheduled)="onEventScheduled($event)"
(dateAndTimeSelected)="onDateSelected($event)"
></ng-calendly-inline>
`
})
export class SchedulingComponent {
calendlyUrl = 'https://calendly.com/your-username/30min';
onEventScheduled(event: CalendlyEvent) {
console.log('Meeting scheduled!', event);
// Send to analytics, show confirmation, etc.
}
onDateSelected(event: CalendlyEvent) {
console.log('Date selected:', event);
}
}Popup Widget
Open Calendly in a modal overlay with a customizable trigger button.
Basic Example:
import { Component } from '@angular/core';
import { CalendlyPopupComponent } from 'angular-calendly';
@Component({
selector: 'app-booking',
standalone: true,
imports: [CalendlyPopupComponent],
template: `
<ng-calendly-popup
[url]="calendlyUrl"
[buttonText]="'Schedule a meeting'"
></ng-calendly-popup>
`
})
export class BookingComponent {
calendlyUrl = 'https://calendly.com/your-username/30min';
}Custom Button Styling:
@Component({
selector: 'app-booking',
standalone: true,
imports: [CalendlyPopupComponent],
template: `
<ng-calendly-popup
[url]="calendlyUrl"
[buttonClass]="'btn btn-primary btn-lg'"
[buttonText]="'Book Your Appointment'"
></ng-calendly-popup>
`,
styles: [`
.btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
font-size: 16px;
cursor: pointer;
}
.btn-primary {
background: #0066ff;
color: white;
}
.btn-primary:hover {
background: #0052cc;
}
`]
})
export class BookingComponent {
calendlyUrl = 'https://calendly.com/your-username/30min';
}Custom Content:
@Component({
selector: 'app-booking',
standalone: true,
imports: [CalendlyPopupComponent],
template: `
<ng-calendly-popup [url]="calendlyUrl">
<div class="custom-button">
<span class="icon">📅</span>
<span>Schedule Now</span>
</div>
</ng-calendly-popup>
`
})
export class BookingComponent {
calendlyUrl = 'https://calendly.com/your-username/30min';
}Programmatic Control
Control the popup widget programmatically using component references or utility functions.
Using ViewChild:
import { Component, ViewChild } from '@angular/core';
import { CalendlyPopupComponent } from 'angular-calendly';
@Component({
selector: 'app-booking',
standalone: true,
imports: [CalendlyPopupComponent],
template: `
<ng-calendly-popup
[url]="calendlyUrl"
[hideButton]="true"
#calendlyPopup
></ng-calendly-popup>
<button (click)="openBooking()">Book a Meeting</button>
<button (click)="closeBooking()">Cancel</button>
`
})
export class BookingComponent {
@ViewChild('calendlyPopup') calendlyPopup!: CalendlyPopupComponent;
calendlyUrl = 'https://calendly.com/your-username/30min';
openBooking() {
this.calendlyPopup.openPopup();
}
closeBooking() {
this.calendlyPopup.closePopup();
}
}Using Utility Functions:
import { Component } from '@angular/core';
import { openCalendlyPopup, closeCalendlyPopup } from 'angular-calendly';
@Component({
selector: 'app-booking',
standalone: true,
template: `
<button (click)="openBooking()">Book a Meeting</button>
`
})
export class BookingComponent {
openBooking() {
openCalendlyPopup('https://calendly.com/your-username/30min');
}
closeBooking() {
closeCalendlyPopup();
}
}API Reference
CalendlyInlineComponent
Embeds Calendly directly in your page.
Inputs
| Property | Type | Required | Default | Description |
|----------|------|----------|---------|-------------|
| url | string | ✅ Yes | - | Your Calendly scheduling page URL |
| prefill | CalendlyPrefill | No | undefined | Prefill user information |
| utm | CalendlyUtm | No | undefined | UTM parameters for tracking |
| backgroundColor | string | No | undefined | Background color (hex without #) |
| textColor | string | No | undefined | Text color (hex without #) |
| primaryColor | string | No | undefined | Primary/accent color (hex without #) |
| hideEventTypeDetails | boolean | No | false | Hide event type details |
| hideLandingPageDetails | boolean | No | false | Hide landing page details |
| hideGdprBanner | boolean | No | false | Hide GDPR consent banner |
| height | number | No | 700 | Widget height in pixels |
| minWidth | number | No | 320 | Minimum width in pixels |
Outputs
| Event | Type | Description |
|-------|------|-------------|
| profilePageViewed | EventEmitter<CalendlyEvent> | Fired when the profile page is viewed |
| eventTypeViewed | EventEmitter<CalendlyEvent> | Fired when an event type page is viewed |
| dateAndTimeSelected | EventEmitter<CalendlyEvent> | Fired when a date and time are selected |
| eventScheduled | EventEmitter<CalendlyEvent> | Fired when an event is successfully scheduled |
CalendlyPopupComponent
Opens Calendly in a modal overlay.
Inputs
| Property | Type | Required | Default | Description |
|----------|------|----------|---------|-------------|
| url | string | ✅ Yes | - | Your Calendly scheduling page URL |
| prefill | CalendlyPrefill | No | undefined | Prefill user information |
| utm | CalendlyUtm | No | undefined | UTM parameters for tracking |
| backgroundColor | string | No | undefined | Background color (hex without #) |
| textColor | string | No | undefined | Text color (hex without #) |
| primaryColor | string | No | undefined | Primary/accent color (hex without #) |
| hideEventTypeDetails | boolean | No | false | Hide event type details |
| hideLandingPageDetails | boolean | No | false | Hide landing page details |
| hideGdprBanner | boolean | No | false | Hide GDPR consent banner |
| buttonText | string | No | 'Schedule time with me' | Text for the trigger button |
| buttonClass | string | No | undefined | CSS class(es) for the button |
| buttonStyle | string | No | undefined | Inline styles for the button |
| hideButton | boolean | No | false | Hide the default button (for programmatic use) |
| autoOpen | boolean | No | false | Automatically open on component init |
Outputs
| Event | Type | Description |
|-------|------|-------------|
| profilePageViewed | EventEmitter<CalendlyEvent> | Fired when the profile page is viewed |
| eventTypeViewed | EventEmitter<CalendlyEvent> | Fired when an event type page is viewed |
| dateAndTimeSelected | EventEmitter<CalendlyEvent> | Fired when a date and time are selected |
| eventScheduled | EventEmitter<CalendlyEvent> | Fired when an event is successfully scheduled |
| popupClosed | EventEmitter<void> | Fired when the popup is closed |
Methods
| Method | Returns | Description |
|--------|---------|-------------|
| openPopup() | void | Programmatically open the popup |
| closePopup() | void | Programmatically close the popup |
TypeScript Interfaces
CalendlyPrefill
interface CalendlyPrefill {
name?: string; // Full name
email?: string; // Email address
firstName?: string; // First name
lastName?: string; // Last name
customAnswers?: Record<string, string>; // Custom question answers
guests?: string[]; // Guest email addresses
date?: Date; // Pre-selected date
}CalendlyUtm
interface CalendlyUtm {
utmCampaign?: string; // Campaign name
utmSource?: string; // Traffic source
utmMedium?: string; // Marketing medium
utmContent?: string; // Ad content
utmTerm?: string; // Search term
}CalendlyEvent
interface CalendlyEvent {
event: string;
payload?: {
event?: {
uri?: string;
};
invitee?: {
uri?: string;
};
};
}Utility Functions
openCalendlyPopup()
function openCalendlyPopup(url: string): voidOpens a Calendly popup with the specified URL.
closeCalendlyPopup()
function closeCalendlyPopup(): voidCloses any open Calendly popup.
isCalendlyEvent()
function isCalendlyEvent(event: MessageEvent): booleanChecks if a message event originated from Calendly.
Example:
window.addEventListener('message', (e) => {
if (isCalendlyEvent(e)) {
console.log('Calendly event received:', e.data);
}
});Advanced Usage
Custom Styling
Customize the widget appearance to match your brand:
<ng-calendly-inline
[url]="calendlyUrl"
[primaryColor]="'0066ff'"
[backgroundColor]="'ffffff'"
[textColor]="'333333'"
></ng-calendly-inline>Note: Provide hex colors without the # symbol.
UTM Tracking
Track campaign performance by adding UTM parameters:
import { CalendlyUtm } from 'angular-calendly';
utmParams: CalendlyUtm = {
utmCampaign: 'spring_sale_2024',
utmSource: 'website',
utmMedium: 'banner',
utmContent: 'hero_section',
utmTerm: 'book_now'
};
// In template
<ng-calendly-inline
[url]="calendlyUrl"
[utm]="utmParams"
></ng-calendly-inline>Custom Answers
Pre-fill custom question answers:
prefillData: CalendlyPrefill = {
name: 'John Doe',
email: '[email protected]',
customAnswers: {
'a1': 'Enterprise Plan',
'a2': 'Referral'
}
};Complete Example
A fully configured widget with all features:
import { Component } from '@angular/core';
import {
CalendlyInlineComponent,
CalendlyPrefill,
CalendlyUtm,
CalendlyEvent
} from 'angular-calendly';
@Component({
selector: 'app-advanced-scheduling',
standalone: true,
imports: [CalendlyInlineComponent],
template: `
<div class="scheduling-container">
<h2>Book Your Consultation</h2>
<ng-calendly-inline
[url]="calendlyUrl"
[height]="800"
[prefill]="prefillData"
[utm]="utmParams"
[primaryColor]="'0066ff'"
[hideGdprBanner]="true"
(profilePageViewed)="onProfileViewed()"
(eventTypeViewed)="onEventTypeViewed()"
(dateAndTimeSelected)="onDateSelected($event)"
(eventScheduled)="onEventScheduled($event)"
></ng-calendly-inline>
</div>
`,
styles: [`
.scheduling-container {
max-width: 1000px;
margin: 0 auto;
padding: 2rem;
}
`]
})
export class AdvancedSchedulingComponent {
calendlyUrl = 'https://calendly.com/your-username/consultation';
prefillData: CalendlyPrefill = {
name: 'Jane Smith',
email: '[email protected]',
customAnswers: {
'a1': 'Premium Plan'
}
};
utmParams: CalendlyUtm = {
utmCampaign: 'website_2024',
utmSource: 'organic',
utmMedium: 'web'
};
onProfileViewed() {
console.log('User viewing profile');
}
onEventTypeViewed() {
console.log('User viewing event types');
}
onDateSelected(event: CalendlyEvent) {
console.log('Date selected:', event);
// Track in analytics
}
onEventScheduled(event: CalendlyEvent) {
console.log('Event scheduled:', event);
// Show success message
// Send confirmation email
// Update database
}
}Examples
Integration with Module-based Apps
If you're using NgModules instead of standalone components:
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CalendlyInlineComponent, CalendlyPopupComponent } from 'angular-calendly';
@NgModule({
imports: [
BrowserModule,
CalendlyInlineComponent, // Import as module
CalendlyPopupComponent
],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule { }Responsive Height
Adjust widget height based on screen size:
import { Component, HostListener } from '@angular/core';
import { CalendlyInlineComponent } from 'angular-calendly';
@Component({
selector: 'app-responsive-scheduling',
standalone: true,
imports: [CalendlyInlineComponent],
template: `
<ng-calendly-inline
[url]="calendlyUrl"
[height]="widgetHeight"
></ng-calendly-inline>
`
})
export class ResponsiveSchedulingComponent {
calendlyUrl = 'https://calendly.com/your-username/30min';
widgetHeight = 700;
@HostListener('window:resize', ['$event'])
onResize() {
this.widgetHeight = window.innerWidth < 768 ? 600 : 800;
}
ngOnInit() {
this.onResize();
}
}SSR Support
This library fully supports Server-Side Rendering (Angular Universal). The components automatically detect the platform and only load Calendly scripts in the browser environment.
No additional configuration needed!
// Works out of the box with Angular Universal
import { CalendlyInlineComponent } from 'angular-calendly';
@Component({
selector: 'app-booking',
standalone: true,
imports: [CalendlyInlineComponent],
template: `
<ng-calendly-inline [url]="url"></ng-calendly-inline>
`
})
export class BookingComponent {
url = 'https://calendly.com/your-username/30min';
}Troubleshooting
Widget Not Appearing
Problem: The widget doesn't show up on the page.
Solutions:
- Verify your Calendly URL is correct and publicly accessible
- Check browser console for errors
- Ensure you have an internet connection (widget loads external scripts)
- Wait a moment - the script loads asynchronously
TypeScript Errors
Problem: TypeScript compilation errors.
Solution: Make sure you're using Angular 18+ and TypeScript 5+:
npm list @angular/core typescriptEvents Not Firing
Problem: Event callbacks aren't being called.
Solution: Ensure you're using the correct event names and syntax:
// ✅ Correct
(eventScheduled)="onEventScheduled($event)"
// ❌ Incorrect
(onEventScheduled)="onEventScheduled($event)"Colors Not Applying
Problem: Custom colors aren't showing.
Solution: Provide hex colors without the # symbol:
// ✅ Correct
[primaryColor]="'0066ff'"
// ❌ Incorrect
[primaryColor]="'#0066ff'"SSR Errors
Problem: Errors during server-side rendering.
Solution: The library handles SSR automatically. If you see window/document errors, ensure you're not accessing browser APIs directly in your component initialization.
Requirements
- Angular: 18.0.0 or higher
- TypeScript: 5.0.0 or higher
- Node.js: 18.0.0 or higher (for development)
Browser Support
- ✅ Chrome (latest)
- ✅ Firefox (latest)
- ✅ Safari (latest)
- ✅ Edge (latest)
- ✅ Mobile browsers (iOS Safari, Chrome Mobile)
Contributing
Contributions are welcome! Here's how you can help:
- Report bugs - Open an issue with details
- Suggest features - Share your ideas
- Submit PRs - Fix bugs or add features
- Improve docs - Help others understand the library
Development Setup
# Clone the repository
git clone https://github.com/your-username/angular-calendly.git
# Install dependencies
npm install
# Build the library
npm run build
# Run demo app
npm startLicense
MIT License - feel free to use this library in your projects!
Support
- 📖 Documentation: README.md
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
Acknowledgments
- Built for Calendly
- Inspired by react-calendly
- Maintained by the community
Made with ❤️ for the Angular community
