Skip to main content
Integration blocks provide ready-to-use components for popular third-party services like calendar booking, customer support, and more.

Cal.com

Integrate Cal.com calendar booking and scheduling into your Reflex application.

Installation

The Cal.com integration uses @calcom/[email protected] which is automatically imported.

Basic Usage

import reflex as rx
from reflex_ui.blocks.calcom import cal_embed, calcom_popup_embed, get_cal_attrs
import reflex_ui as ui

# Embed calendar directly
def cal_embed_example():
    return cal_embed(
        cal_link="forms/f87bd9b2-b339-4915-b4d4-0098e2db4394",
        config={"theme": "light", "layout": "month_view"},
    )

# Popup embed with button trigger
def cal_popup_example():
    return rx.fragment(
        ui.button(
            "Schedule a Call",
            **get_cal_attrs(
                "forms/f87bd9b2-b339-4915-b4d4-0098e2db4394"
            ),
        ),
        calcom_popup_embed(),
    )

Components

cal_embed

Embed a Cal.com calendar directly in your page.
The Cal.com form link (e.g., “forms/YOUR-FORM-ID” or “username/event-type”).
config
dict
Configuration object for the calendar. Common options:
  • theme: “light” or “dark”
  • layout: “month_view”, “week_view”, or “column_view”

calcom_popup_embed

Adds Cal.com popup functionality. Use with get_cal_attrs() on a trigger element.

get_cal_attrs(cal_form, **kwargs)

Generates Cal.com data attributes for popup embeds.
cal_form
str
The Cal.com form link.
**kwargs
dict
Additional data attributes to include.
Returns a dictionary of data attributes to spread on a button or link.

Configuration

Set the default Cal.com form via environment variable:
DEFAULT_CAL_FORM="forms/your-form-id"

Advanced Example

import reflex as rx
from reflex_ui.blocks.calcom import calcom_popup_embed, get_cal_attrs
import reflex_ui as ui

def booking_page():
    return rx.container(
        rx.heading("Schedule a Meeting"),
        ui.button(
            "Book a 30-min Call",
            **get_cal_attrs(
                "team/sales/30min",
                **{"data-cal-config": '{"theme":"auto"}'}
            ),
        ),
        calcom_popup_embed(),
    )

Lemcal

Integrate Lemcal meeting scheduler with a dialog-based booking interface.

Installation

Lemcal integration uses the Lemcal CDN script which is automatically loaded.

Basic Usage

import reflex as rx
from reflex_ui.blocks.lemcal import lemcal_dialog, lemcal_booking_calendar
import reflex_ui as ui

# Dialog with trigger button
def lemcal_dialog_example():
    return lemcal_dialog(
        trigger=ui.button("Schedule a Demo"),
    )

# Embedded calendar
def lemcal_embed_example():
    return rx.box(
        lemcal_booking_calendar(),
        class_name="h-screen",
    )

Components

lemcal_dialog(trigger, **props)

Creates a dialog with the Lemcal booking calendar.
trigger
rx.Component
The component that opens the dialog when clicked.
class_name
str
Additional CSS classes for the dialog container.

lemcal_booking_calendar()

Returns the Lemcal booking calendar component. Memoized for performance.

lemcal_script(**props)

Returns the Lemcal integration script tag. Usually not needed directly as it’s included in lemcal_booking_calendar().

Configuration

The default Lemcal configuration is set in the component:
LEMCAL_DEMO_URL = "https://app.lemcal.com/@alek/reflex-demo-call"

# User ID and meeting type are configured via data attributes
data_user="usr_8tiwtJ8nEJaFj2qH9"
data_meeting_type="met_EHtPvmZoKE4SFk4kZ"
To use your own Lemcal account, modify these values in your implementation.

Example

import reflex as rx
from reflex_ui.blocks.lemcal import lemcal_dialog
import reflex_ui as ui

def hero_section():
    return rx.box(
        rx.heading("Talk to Our Team"),
        rx.text("Schedule a personalized demo"),
        lemcal_dialog(
            trigger=ui.button(
                "Book Your Demo",
                size="lg",
            ),
        ),
    )

Plain

Integrate Plain.com customer support chat widget into your application.

Installation

The Plain integration automatically loads the Plain chat script from their CDN.

Basic Usage

import reflex as rx
from reflex_ui.blocks.plain import plain_chat, open_plain_chat
import reflex_ui as ui

class ChatState(rx.State):
    user_name: str = "John Doe"
    user_email: str = "[email protected]"

def app_with_support():
    return rx.fragment(
        # Add chat widget
        plain_chat(
            full_name=ChatState.user_name,
            email=ChatState.user_email,
        ),
        
        # Button to open chat
        ui.button(
            "Contact Support",
            on_click=open_plain_chat(),
        ),
    )

Components

plain_chat(**props)

Initializes the Plain chat widget with customer information.
full_name
str
default:"User"
User’s full name displayed in the chat.
short_name
str
default:"User"
Short name or first name for the user.
chat_avatar_url
str
URL to the user’s avatar image.
external_id
str
Your internal user ID for tracking.
email
str
User’s email address.
email_hash
str
HMAC hash of the email for authentication.
hide_launcher
bool
default:"true"
Whether to hide the default chat launcher. Set to False to show Plain’s default launcher button.
require_authentication
bool
default:"false"
Whether to require email verification before chatting.
tier_id
str
Customer tier identifier for thread details.
entry_point_type
str
Entry point type: “default” (shows intro screen) or “chat” (opens directly to chat).
entry_point_external_id
str
External ID of which chat to open. Defaults to last conversation.
single_chat_mode
bool
default:"false"
Prevents user from going back to intro screen to start a new chat.

open_plain_chat()

Returns an event that opens the Plain chat widget.

Configuration

Set your Plain app ID via environment variable:
PLAIN_APP_ID="liveChatApp_YOUR_APP_ID"

Advanced Examples

With Authentication

import reflex as rx
from reflex_ui.blocks.plain import plain_chat
import hashlib
import hmac

class SupportState(rx.State):
    user_email: str = "[email protected]"
    
    @rx.var
    def email_hash(self) -> str:
        # Generate HMAC hash for email verification
        secret = "your-plain-secret-key"
        return hmac.new(
            secret.encode(),
            self.user_email.encode(),
            hashlib.sha256
        ).hexdigest()

def authenticated_chat():
    return plain_chat(
        email=SupportState.user_email,
        email_hash=SupportState.email_hash,
        require_authentication=True,
    )

With User Context

import reflex as rx
from reflex_ui.blocks.plain import plain_chat, open_plain_chat
import reflex_ui as ui

class UserState(rx.State):
    user_id: str = "user_123"
    name: str = "Jane Smith"
    email: str = "[email protected]"
    avatar: str = "https://example.com/avatar.jpg"
    tier: str = "enterprise"

def support_widget():
    return rx.fragment(
        plain_chat(
            full_name=UserState.name,
            short_name=UserState.name.split()[0],
            email=UserState.email,
            chat_avatar_url=UserState.avatar,
            external_id=UserState.user_id,
            tier_id=UserState.tier,
            entry_point_type="chat",
        ),
        
        ui.button(
            "Get Help",
            on_click=open_plain_chat(),
            class_name="fixed bottom-4 right-4",
        ),
    )

Custom Launcher

import reflex as rx
from reflex_ui.blocks.plain import plain_chat, open_plain_chat
import reflex_ui as ui

def custom_support_launcher():
    return rx.fragment(
        # Initialize chat with hidden launcher
        plain_chat(
            hide_launcher=True,
            full_name="Customer",
        ),
        
        # Custom support button
        rx.box(
            ui.button(
                ui.hi("MessageChatCircleIcon", size=24),
                "Need Help?",
                on_click=open_plain_chat(),
                size="lg",
            ),
            class_name="fixed bottom-6 right-6 z-50",
        ),
    )

Build docs developers (and LLMs) love