Themes, slots, and headless composition for Alaznah Calling UI.
Customization
You can restyle the built-in UI, replace parts with slots, or ignore screens entirely and drive the client from hooks.
Theme
import { CallingUI, defaultCallingTheme, mergeTheme } from '@alaznah/calling';
const theme = mergeTheme(defaultCallingTheme, {
colors: {
accent: '#2563eb',
danger: '#e83829',
background: '#0b1220',
},
});
<CallingUI theme={theme} />Theme tokens control surfaces used by incoming / active screens (background, accent, danger, text, …). Exact keys live on CallingTheme — start from defaultCallingTheme and override what you need.
Backgrounds
Many screens accept backgroundColor and/or backgroundImage for branded ringing / active layouts:
<CallingUI
backgroundColor="#0b1220"
backgroundImage={require('./assets/call-bg.png')}
/>Slots
CallingUISlots lets you override pieces without rewriting the whole tree — for example custom header, avatar, or control row. Pass slots into CallingUI / screen components:
<CallingUI
slots={{
renderHeader: (call) => <MyHeader peerId={call.peerId} />,
renderStatus: (call) => <Text>{call.state}</Text>,
}}
/>See Props and UI Components for the full slot surface available in your SDK version.
Headless (no built-in screens)
function MyCallHost() {
const client = useCallingClient();
const call = useCall();
const incoming = useIncomingCall();
if (incoming) {
return (
<MyIncoming
call={incoming}
onAccept={() => client.accept(incoming.callId)}
onReject={() => client.reject(incoming.callId, 'declined')}
/>
);
}
if (call) {
return (
<MyActive
call={call}
onMute={(m) => client.setMuted(m)}
onEnd={() => client.end(call.callId)}
/>
);
}
return <MyDialer onCall={(id) => client.startCall({ calleeId: id })} />;
}If you ship a custom incoming UI, still call drainNativeIncomingAction + syncPendingCalls on resume — see Incoming Calls.
Keep native & JS in sync
When your custom UI is visible, suppress duplicate native incoming notifications:
useEffect(() => {
client.setNativeIncomingSuppressed(true);
return () => client.setNativeIncomingSuppressed(false);
}, [client]);