Framework Integration
Using Resytech web components with React, Vue, Svelte, Angular, and other frameworks.
Resytech web components are standard Custom Elements. They work in any framework that renders HTML, but each framework has slightly different patterns for setting properties and listening to events.
Vue
Vue has full web component support out of the box. Use v-bind for properties and v-on for events.
<template>
<resytech-activity-list @activity-select="onActivitySelect" />
<resytech-equipment-list
:activity-id="selectedActivity?.uuid"
@equipment-select="onEquipmentSelect"
/>
<resytech-calendar
ref="calendar"
:show-prices="true"
@date-select="onDateSelect"
/>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const selectedActivity = ref(null);
const calendar = ref(null);
onMounted(async () => {
const api = new ResytechApi();
await api.initialization.initialize({ identifier: 'my-site' });
api.registerComponents();
});
function onActivitySelect(e) {
selectedActivity.value = e.detail.activity;
}
function onEquipmentSelect(e) {
// Set object properties via ref for complex data
calendar.value.activityId = selectedActivity.value.uuid;
calendar.value.load();
}
function onDateSelect(e) {
console.log('Selected:', e.detail.date);
}
</script>Vue Compiler Hint
Vue may warn about unknown custom elements. Tell the compiler to treat resytech-* tags as custom elements:
// vite.config.js
import vue from '@vitejs/plugin-vue';
export default {
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('resytech-')
}
}
})
]
};Svelte
Svelte handles web components natively. Use on: for events and bind:this for property access.
<script>
import { onMount } from 'svelte';
let calendarEl;
let selectedActivity = null;
onMount(async () => {
const api = new ResytechApi();
await api.initialization.initialize({ identifier: 'my-site' });
api.registerComponents();
});
function onActivitySelect(e) {
selectedActivity = e.detail.activity;
}
function onEquipmentSelect(e) {
calendarEl.activityId = selectedActivity.uuid;
calendarEl.load();
}
function onDateSelect(e) {
console.log('Selected:', e.detail.date);
}
</script>
<resytech-activity-list on:activity-select={onActivitySelect} />
<resytech-equipment-list
activity-id={selectedActivity?.uuid}
on:equipment-select={onEquipmentSelect}
/>
<resytech-calendar
bind:this={calendarEl}
show-prices="true"
on:date-select={onDateSelect}
/>No additional configuration needed.
React 19+
React 19 added native support for custom elements. Properties, events, and refs all work as expected.
import { useRef, useEffect, useState } from 'react';
function BookingPage() {
const calendarRef = useRef(null);
const [selectedActivity, setSelectedActivity] = useState(null);
useEffect(() => {
const api = new ResytechApi();
api.initialization.initialize({ identifier: 'my-site' }).then(() => {
api.registerComponents();
});
}, []);
return (
<>
<resytech-activity-list
onActivitySelect={(e) => setSelectedActivity(e.detail.activity)}
/>
<resytech-equipment-list
activity-id={selectedActivity?.uuid}
onEquipmentSelect={(e) => {
calendarRef.current.activityId = selectedActivity.uuid;
calendarRef.current.load();
}}
/>
<resytech-calendar
ref={calendarRef}
show-prices="true"
onDateSelect={(e) => console.log('Selected:', e.detail.date)}
/>
</>
);
}React 19 maps onEventName props to custom element event listeners automatically. The event name is derived by lowercasing: onActivitySelect listens for activityselect. Since our events use kebab-case (activity-select), you may need to use the ref approach below for event listeners.
React 19 — Ref Approach (Recommended)
For reliable event handling with kebab-case event names, use refs:
import { useRef, useEffect, useState } from 'react';
function BookingPage() {
const listRef = useRef(null);
const [selectedActivity, setSelectedActivity] = useState(null);
useEffect(() => {
const el = listRef.current;
const handler = (e) => setSelectedActivity(e.detail.activity);
el.addEventListener('activity-select', handler);
return () => el.removeEventListener('activity-select', handler);
}, []);
return <resytech-activity-list ref={listRef} />;
}React 18 and Earlier
React 18 does not natively support custom element properties or events in JSX. Use refs for everything.
import { useRef, useEffect, useState } from 'react';
function ActivityList() {
const ref = useRef(null);
const [selected, setSelected] = useState(null);
useEffect(() => {
const el = ref.current;
// Listen for custom events via addEventListener
const handler = (e) => setSelected(e.detail.activity);
el.addEventListener('activity-select', handler);
return () => el.removeEventListener('activity-select', handler);
}, []);
return <resytech-activity-list ref={ref} />;
}
function EquipmentList({ activity }) {
const ref = useRef(null);
useEffect(() => {
if (ref.current && activity) {
// Set complex object properties via ref (JSX only passes strings)
ref.current.activity = activity;
}
}, [activity]);
return <resytech-equipment-list ref={ref} />;
}
function Calendar({ activityId, durationId }) {
const ref = useRef(null);
useEffect(() => {
if (ref.current && activityId) {
ref.current.activityId = activityId;
ref.current.durationId = durationId;
ref.current.load();
}
}, [activityId, durationId]);
useEffect(() => {
const el = ref.current;
const handler = (e) => console.log('Date:', e.detail.date);
el.addEventListener('date-select', handler);
return () => el.removeEventListener('date-select', handler);
}, []);
return <resytech-calendar ref={ref} show-prices="true" />;
}TypeScript Declarations for React
If TypeScript complains about unknown JSX elements, add type declarations:
// resytech.d.ts
declare namespace JSX {
interface IntrinsicElements {
'resytech-activity-card': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
'activity-id'?: string;
'show-tagline'?: string;
'show-description'?: string;
'show-price'?: string;
};
'resytech-activity-list': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
'show-title'?: string;
'title-text'?: string;
};
'resytech-equipment-list': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
'activity-id'?: string;
'show-title'?: string;
};
'resytech-calendar': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
'activity-id'?: string;
'duration-id'?: string;
'show-prices'?: string;
};
'resytech-timeslots': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
'activity-id'?: string;
date?: string;
'duration-id'?: string;
};
'resytech-addon-selector': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
'activity-id'?: string;
date?: string;
time?: string;
};
'resytech-cart-summary': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;
'resytech-duration-selector': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;
'resytech-booking-embed': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
'base-url'?: string;
'location-id'?: string;
'activity-id'?: string;
height?: string;
};
}
}Angular
Angular supports web components via the CUSTOM_ELEMENTS_SCHEMA:
// app.module.ts
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {}<!-- app.component.html -->
<resytech-activity-list
(activity-select)="onActivitySelect($event)">
</resytech-activity-list>
<resytech-calendar
#calendar
[attr.activity-id]="selectedActivity?.uuid"
[attr.show-prices]="'true'"
(date-select)="onDateSelect($event)">
</resytech-calendar>// app.component.ts
@ViewChild('calendar') calendarRef: ElementRef;
onActivitySelect(event: CustomEvent) {
this.selectedActivity = event.detail.activity;
this.calendarRef.nativeElement.activityId = this.selectedActivity.uuid;
this.calendarRef.nativeElement.load();
}Vanilla JavaScript
No framework needed. The components work directly in HTML:
<script src="https://js.resytech.com/1/resytech.js"></script>
<script>
const api = new ResytechApi();
api.initialization.initialize({ identifier: 'my-site' }).then(() => {
api.registerComponents();
});
document.addEventListener('activity-select', (e) => {
console.log(e.detail.activity.name);
});
</script>
<resytech-activity-list></resytech-activity-list>Summary
| Framework | Attributes | Object Properties | Custom Events | Extra Config |
|---|---|---|---|---|
| Vanilla JS | Native | Native | Native | None |
| Vue | Native | v-bind / ref | v-on | isCustomElement compiler option |
| Svelte | Native | bind:this | on:event | None |
| React 19+ | Native | ref | ref + addEventListener | None |
| React 18 | Native | ref only | ref + addEventListener | TypeScript declarations |
| Angular | [attr.x] | ViewChild + .nativeElement | (event) | CUSTOM_ELEMENTS_SCHEMA |
