Alaznah

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

tsx
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:

tsx
<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:

tsx
<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)

tsx
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:

ts
useEffect(() => {
  client.setNativeIncomingSuppressed(true);
  return () => client.setNativeIncomingSuppressed(false);
}, [client]);