Framework integrations
The Fluid widgets are standard web components, so they work in any framework. Every integration follows the same three rules regardless of the framework:
- Load the Fluid script once, after the user authenticates, and never on every render.
- Pass the real, current
session-idof the authenticated user and keep it stable. See Session handling. - Register event listeners (and any Bridge API handlers) only after the script has loaded.
If your integration uses the Bridge API, register all bridge handlers inside the script.onload callback, never in code that runs synchronously after document.head.appendChild(script). Because scripts created via document.createElement('script') are asynchronous by default, window.fluid.bridge will not exist until after onload fires.
Object valued attributes (user-data, bonuses, transaction-attributes) are passed as stringified JSON in every framework. See Data objects for their shapes.
React
React sets unknown attributes on custom elements as strings, which suits the Fluid attributes. Guard the script injection so React does not load it twice, and attach listeners with useLayoutEffect:
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
type FluidWrapperProps = {
operatorId: string;
userId: string;
sessionId: string;
locale: string;
country: string;
currency: string;
open: boolean;
transaction: 'deposit' | 'withdrawal' | 'quick-deposit';
balance: number;
withdrawableBalance: number;
userData: object;
bonuses: object[];
onInfo: (event: Event) => void;
onCommand: (event: Event) => void;
onError: (event: Event) => void;
};
let scriptLoaded = false;
function FluidWrapper({
operatorId, userId, sessionId, locale, country, currency,
open, transaction, balance, withdrawableBalance, userData, bonuses,
onInfo, onCommand, onError
}: FluidWrapperProps) {
const ref = useRef(null);
useEffect(() => {
if (!scriptLoaded) {
const script = document.createElement('script');
script.src = 'https://get.fluidpayments.io/index.js';
script.onload = () => {
// register window.fluid.bridge handlers here if you use the Bridge API
};
document.head.appendChild(script);
scriptLoaded = true;
}
}, []);
useLayoutEffect(() => {
const fluid = ref.current;
fluid.addEventListener('fluid-command', onCommand);
fluid.addEventListener('fluid-info', onInfo);
fluid.addEventListener('fluid-error', onError);
return () => {
fluid.removeEventListener('fluid-command', onCommand);
fluid.removeEventListener('fluid-info', onInfo);
fluid.removeEventListener('fluid-error', onError);
}
}, [onCommand, onError, onInfo, ref]);
return (
<fluid-widget
ref={ref}
operator-id={operatorId}
user-id={userId}
session-id={sessionId}
locale={locale}
country={country}
currency={currency}
user-data={JSON.stringify(userData)}
bonuses={JSON.stringify(bonuses || [])}
transaction={transaction}
open={open}
balance={balance}
withdrawable-balance={withdrawableBalance}>
</fluid-widget>
);
}
The scriptLoaded flag prevents React from loading the widget script twice on render; the script stays on the page for its whole lifetime, as the custom element definition cannot be unloaded. session-id must be the real, current session ID of the authenticated user, kept stable for the session; see Session handling.
The host component supplies the values from its own state and reacts to the close command by flipping the open state:
function Cashier({ user }: { user: AuthenticatedUser }) {
const [open, setOpen] = useState(false);
const [ready, setReady] = useState(false);
function onInfo(event: Event) {
if ((event as CustomEvent).detail.message === 'initialised') {
setReady(true);
}
}
function onCommand(event: Event) {
if ((event as CustomEvent).detail.message === 'close') {
setOpen(false);
}
}
return (
<>
<button disabled={!ready} onClick={() => setOpen(true)}>Deposit</button>
<FluidWrapper
operatorId="<your operator id>"
userId={user.id}
sessionId={user.sessionId}
locale={user.locale}
country={user.country}
currency={user.currency}
open={open}
transaction="deposit"
balance={user.balance}
withdrawableBalance={user.withdrawableBalance}
userData={user.fluidUserData}
bonuses={user.bonuses}
onInfo={onInfo}
onCommand={onCommand}
onError={(event) => console.error('Fluid error:', (event as CustomEvent).detail.message)}
/>
</>
);
}
A complete working example is available at https://github.com/soltechno/fluid-react-integration (live at https://fluid-react-integration.vercel.app).
Angular
Add CUSTOM_ELEMENTS_SCHEMA to the component (or module) so Angular accepts the unknown element, and bind attributes with the attr. prefix:
<fluid-widget
[attr.operator-id]="config.operatorId"
[attr.user-id]="session.userId"
[attr.session-id]="session.sessionId"
[attr.locale]="session.locale"
[attr.country]="session.countryCode"
[attr.currency]="session.currencyCode"
[attr.user-data]="userData | json"
[attr.transaction]="transaction"
[attr.open]="open"
[attr.balance]="balance"
[attr.withdrawable-balance]="withdrawableBalance">
</fluid-widget>
Attach the event listeners to the element after the view initialises, for example with an ElementRef in ngAfterViewInit, and load the script once in a service when the user authenticates.
A complete working example is available at https://github.com/soltechno/fluid-angular (live at https://demo.fluidpayments.io).
Vue
Configure Vue to treat fluid- elements as custom elements (compilerOptions.isCustomElement = (tag) => tag.startsWith('fluid-')), then bind attributes normally:
<fluid-widget
:operator-id="config.operatorId"
:user-id="session.userId"
:session-id="session.sessionId"
:locale="session.locale"
:country="session.countryCode"
:currency="session.currencyCode"
:user-data="JSON.stringify(userData)"
:transaction="transaction"
:open="open"
:balance="balance"
:withdrawable-balance="withdrawableBalance">
</fluid-widget>
Attach the event listeners in onMounted using a template ref, and load the script once when the user authenticates.
Svelte
Svelte works with custom elements out of the box. Use the element directly with its kebab-case attributes and Svelte's event syntax:
<fluid-widget
operator-id={config.operatorId}
user-id={session.userId}
session-id={session.sessionId}
locale={session.locale}
country={session.countryCode}
currency={session.currencyCode}
user-data={JSON.stringify(userData)}
transaction={transaction}
open={open}
balance={balance}
withdrawable-balance={withdrawableBalance}
on:fluid-info={onInfo}
on:fluid-command={onCommand}
on:fluid-error={onError}>
</fluid-widget>
Load the script once when the user authenticates, for example in an onMount of your authenticated layout.