Add Custom Header·续

RealtimeKit UI provides the RtkMeetingHeaderView component for a default header.

If you need additional controls, replace RtkMeetingHeaderView with individual UI Kit components and custom elements.

Import the required components:

import com.cloudflare.realtimekit.ui.view.headers.RtkMeetingHeaderView
import com.cloudflare.realtimekit.ui.view.RtkMeetingTitleView
import com.cloudflare.realtimekit.ui.view.RtkParticipantCountView
import com.cloudflare.realtimekit.ui.view.RtkClockView
import com.cloudflare.realtimekit.ui.view.RtkRecordingIndicator
import com.cloudflare.realtimekit.ui.view.RtkLivestreamIndicator
import com.cloudflare.realtimekit.ui.view.RtkGridPaginatorView

Create custom header layout

Create an XML layout file for your custom header:

layout/custom_header.xmlxml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="48dp"
    android:orientation="horizontal"
    android:gravity="center_vertical"
    android:paddingHorizontal="12dp"
    android:background="@android:color/black">

<!-- Left section -->
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="horizontal"
        android:gravity="start|center_vertical">

<com.cloudflare.realtimekit.ui.view.RtkRecordingIndicator
            android:id="@+id/recordingIndicator"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

<com.cloudflare.realtimekit.ui.view.RtkLivestreamIndicator
            android:id="@+id/livestreamIndicator"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp" />
    </LinearLayout>

<!-- Center section -->
    <com.cloudflare.realtimekit.ui.view.RtkMeetingTitleView
        android:id="@+id/meetingTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@android:color/white" />

<!-- Right section -->
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="horizontal"
        android:gravity="end|center_vertical">

<com.cloudflare.realtimekit.ui.view.RtkGridPaginatorView
            android:id="@+id/gridPaginator"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

<com.cloudflare.realtimekit.ui.view.RtkParticipantCountView
            android:id="@+id/participantCount"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp" />

<com.cloudflare.realtimekit.ui.view.RtkClockView
            android:id="@+id/clock"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp" />

<Button
            android:id="@+id/reportBugButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:text="Report Bug"
            android:textColor="@android:color/white"
            android:background="@android:color/transparent"
            style="?android:attr/borderlessButtonStyle" />
    </LinearLayout>
</LinearLayout>

Create custom header view class

CustomHeaderView.ktkotlin

package com.example.meeting

import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.widget.Button
import android.widget.LinearLayout
import com.cloudflare.realtimekit.ui.view.RtkClockView
import com.cloudflare.realtimekit.ui.view.RtkMeetingTitleView
import com.cloudflare.realtimekit.ui.view.RtkParticipantCountView
import com.cloudflare.realtimekit.ui.view.RtkRecordingIndicator

class CustomHeaderView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {

init {
        LayoutInflater.from(context).inflate(R.layout.custom_header, this, true)
        setupReportBugButton()
    }

private fun setupReportBugButton() {
        findViewById<Button>(R.id.reportBugButton).setOnClickListener {
            Log.d("CustomHeader", "Report Bug Clicked")
            // Add your custom logic here
        }
    }
}

Use in your meeting activity

In your MeetingActivity, replace the default header with your custom header:

MeetingActivity.ktkotlin

package com.example.meeting

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.cloudflare.realtimekit.RealtimeKitClient

class MeetingActivity : AppCompatActivity() {
    private lateinit var meeting: RealtimeKitClient
    private lateinit var customHeader: CustomHeaderView

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_meeting)

customHeader = findViewById(R.id.customHeader)
        initializeMeeting()
    }

private fun initializeMeeting() {
        RealtimeKitClient.init(
            authToken = "<PARTICIPANT_AUTH_TOKEN>",
            onSuccess = { client ->
                meeting = client
                // Configure meeting UI
            },
            onError = { error ->
                Log.e("Meeting", "Failed to initialize: $error")
            }
        )
    }
}

RealtimeKit UI provides the RtkHeader component for a default header.

If you need additional controls, replace RtkHeader with individual UI Kit components and custom elements.

Import the required components:

import {
    RtkLogo,
    RtkRecordingIndicator,
    RtkLiveStreamIndicator,
    RtkMeetingTitle,
    RtkGridPagination,
    RtkParticipantCount,
    RtkClock,
} from "@cloudflare/realtimekit-react-native-ui";
import {
    useRealtimeKitMeeting,
    useRealtimeKitSelector,
} from "@cloudflare/realtimekit-react-native";

Create custom header component

Create a custom header component that uses the RealtimeKit React Native components directly. Each component requires the meeting instance as a prop, which you obtain via the useRealtimeKitMeeting hook. The component waits for roomJoined before rendering to ensure the meeting state is ready:

CustomHeader.tsxtsx

import React from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
import {
    RtkLogo,
    RtkRecordingIndicator,
    RtkLiveStreamIndicator,
    RtkMeetingTitle,
    RtkGridPagination,
    RtkParticipantCount,
    RtkClock,
} from "@cloudflare/realtimekit-react-native-ui";
import {
    useRealtimeKitMeeting,
    useRealtimeKitSelector,
} from "@cloudflare/realtimekit-react-native";

interface CustomHeaderProps {
    onReportBugPress?: () => void;
}

export function CustomHeader({ onReportBugPress }: CustomHeaderProps) {
    const { meeting } = useRealtimeKitMeeting();
    const { roomJoined } = useRealtimeKitSelector((state) => state.self);

const handleReportBugPress = () => {
        console.log("Report Bug Pressed");
        onReportBugPress?.();
    };

if (!roomJoined) {
        return null;
    }

return (
        <View style={styles.container}>
            {/* Left section */}
            <View style={styles.leftSection}>
                <RtkLogo />
                <RtkRecordingIndicator meeting={meeting} />
                <RtkLiveStreamIndicator meeting={meeting} />
            </View>

{/* Center section */}
            <View style={styles.centerSection}>
                <RtkMeetingTitle meeting={meeting} />
            </View>

{/* Right section */}
            <View style={styles.rightSection}>
                <RtkGridPagination meeting={meeting} />
                <RtkParticipantCount meeting={meeting} />
                <RtkClock meeting={meeting} />
                <TouchableOpacity
                    style={styles.reportBugButton}
                    onPress={handleReportBugPress}
                >
                    <Text style={styles.reportBugText}>Report Bug</Text>
                </TouchableOpacity>
            </View>
        </View>
    );
}

const styles = StyleSheet.create({
    container: {
        flexDirection: "row",
        justifyContent: "space-between",
        alignItems: "center",
        height: 48,
        paddingHorizontal: 12,
        backgroundColor: "black",
    },
    leftSection: {
        flexDirection: "row",
        alignItems: "center",
        gap: 8,
    },
    centerSection: {
        flexDirection: "row",
        alignItems: "center",
    },
    rightSection: {
        flexDirection: "row",
        alignItems: "center",
        gap: 8,
    },
    reportBugButton: {
        borderWidth: 1,
        borderColor: "white",
        borderRadius: 4,
        paddingHorizontal: 8,
        paddingVertical: 4,
    },
    reportBugText: {
        color: "white",
        fontSize: 12,
    },
});

Note

useRealtimeKitMeeting and useRealtimeKitSelector must be called inside a component rendered within a RealtimeKitProvider. The roomJoined guard ensures the header only renders once the participant has successfully joined the meeting. meeting.join() is called from the parent MeetingScreen so that the join lifecycle is managed in one place.

Use in your meeting screen

In your meeting screen, replace the default RtkHeader with your custom header:

MeetingScreen.tsxtsx

import React, { useEffect } from "react";
import { View, StyleSheet } from "react-native";
import {
    RealtimeKitProvider,
    useRealtimeKitClient,
} from "@cloudflare/realtimekit-react-native";
import {
    RtkGrid,
    RtkControlbar,
    RtkDialogManager,
} from "@cloudflare/realtimekit-react-native-ui";
import { CustomHeader } from "./CustomHeader";

function MeetingContainer() {
    const [meeting, initMeeting] = useRealtimeKitClient();

useEffect(() => {
        initMeeting({
            authToken: "<PARTICIPANT_AUTH_TOKEN>",
        });
    }, [initMeeting]);

useEffect(() => {
        if (!meeting) return;
        meeting.join();
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [meeting]);

if (!meeting) {
        return null;
    }

return (
        <RealtimeKitProvider value={meeting}>
            <View style={styles.container}>
                {/* Custom header replaces RtkHeader */}
                <CustomHeader
                    onReportBugPress={() => console.log("Report bug pressed")}
                />

{/* Meeting grid */}
                <View style={styles.gridContainer}>
                    <RtkGrid meeting={meeting} />
                </View>

{/* Control bar */}
                <RtkControlbar meeting={meeting} />
            </View>

{/* Required components */}
            <RtkDialogManager meeting={meeting} />
        </RealtimeKitProvider>
    );
}

export function MeetingScreen() {
    return <MeetingContainer />;
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: "black",
    },
    gridContainer: {
        flex: 1,
    },
});

Note

You must include RtkDialogManager. If you leave it out, features like settings toggles will not work.

Was this helpful?

YesNo

On this page

Add Custom Header·续 - 图1Docs

{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/realtime/realtimekit/humans/ui-kit/custom-header/#page","headline":"Add Custom Header","description":"Add a custom header to your RealtimeKit meeting UI with individual components.","url":"https://developers.cloudflare.com/realtime/realtimekit/humans/ui-kit/custom-header/","inLanguage":"en","image":"https://developers.cloudflare.com/realtime/realtimekit/humans/ui-kit/custom-header/og.png?v=e73652b1d8137740","dateModified":"2026-10-19","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}


description: Customize text and localize the RealtimeKit UI Kit meeting interface for different languages. title: Meeting Locale image: https://developers.cloudflare.com/realtime/realtimekit/humans/ui-kit/meeting-locale/og.png?v=8f80148548031940


Skip to content

Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/realtime/llms.txt
Use this file to discover all available pages before exploring further.