---
source_url: https://www.pubnub.com/docs/sdks/javascript/quickstart-react-native
title: "Quickstart: PubNub JavaScript SDK in React Native"
updated_at: 2026-11-09T13:29:01.000Z
sdk_name: PubNub JavaScript SDK
sdk_version: 13.1.3
description: Build a React Native app that connects to PubNub, subscribes to a channel, and publishes messages with the JavaScript SDK.
---

# Quickstart: PubNub JavaScript SDK in React Native

PubNub JavaScript SDK, use the latest version: 13.1.3

Install:

```bash
npm install pubnub@13.1.3
```

> For AI agents: documentation index at https://www.pubnub.com/llms-full.txt

Use this quickstart to connect a React Native app to PubNub, subscribe to a channel, and send a message.

:::note Content moved
The steps below are the React Native panels of the former Getting Started page, moved here unchanged. A shorter React Native quickstart that matches the Web and Node.js ones will replace them. For the shortest path to a first message, use [Quickstart: Web](https://www.pubnub.com/docs/sdks/javascript/quickstart-web.md).
:::

## Before you begin

* A React Native development environment set up.
* A PubNub account (you create one below).

### Get your PubNub keys

First, get your PubNub keys:

* [Sign in](https://admin.pubnub.com/#/login) or [create an account](https://admin.pubnub.com/#/signup) on the PubNub Admin Portal
* Create an app (or use an existing one)
* Find your publish and subscribe keys in the app dashboard

When you create an app, PubNub automatically generates a keyset. You can use the same keyset for development and production, but we recommend separate keysets for each environment to improve security and management.

## Install

:::note SDK version
Always use the latest SDK version to have access to the newest features and avoid security vulnerabilities, bugs, and performance issues.
:::

For React Native projects, install the PubNub SDK along with the required `react-native-url-polyfill` peer dependency. The example app in this quickstart also imports `SafeAreaView` from `react-native-safe-area-context`:

```bash
npm install pubnub react-native-url-polyfill react-native-safe-area-context
```

Then import it in your project:

```javascript
import PubNub from 'pubnub';
```

## Initialize

Create an instance of the PubNub class with your keys and a unique user ID:

```tsx
const pubnub = new PubNub({
    publishKey: "demo",
    subscribeKey: "demo",
    userId: "rn-user-" + Math.floor(Math.random() * 1000)
});
```

In a real React Native application, you would typically initialize PubNub inside a component using hooks for proper lifecycle management:

```tsx
// Example of initialization in a React component (optional)
useEffect(() => {
    // Clean up on component unmount
    return () => {
        if (pubnub) {
            pubnub.removeAllListeners();
            pubnub.destroy();
        }
    };
}, [pubnub]);
```

For more information, refer to the [Configuration](https://www.pubnub.com/docs/sdks/javascript/api-reference/configuration.md) section of the SDK documentation.

## Set up event listeners

Listeners help the application react to events and messages. You can implement custom app logic to respond to each type of message or event.

For complete details on subscribing and handling events, refer to the [Publish and Subscribe API Reference](https://www.pubnub.com/docs/sdks/javascript/api-reference/subscribe.md#subscribe).

```tsx
// App.tsx

// Imports
import React, { useState, useEffect, useRef } from 'react';
import {
  StyleSheet,
  View,
  Text,
  TextInput,
  TouchableOpacity,
  FlatList,
  KeyboardAvoidingView,
  Platform,
  StatusBar,
  ActivityIndicator,
  Alert
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import PubNub from 'pubnub';

// Types for the messages
type ChatMessage = {
  text: string;
  sender?: string;
  time?: string;
};

type MessageItem = {
  id: string;
  message: ChatMessage;
};

// Main App Component
export default function App() {
  // State variables
  const [pubnub, setPubnub] = useState<PubNub | null>(null);
  const [messages, setMessages] = useState<MessageItem[]>([]);
  const [inputText, setInputText] = useState('');
  const [isConnected, setIsConnected] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  
  // Reference to the FlatList for auto-scrolling
  const flatListRef = useRef<FlatList>(null);

  // Initialize PubNub on component mount
  useEffect(() => {
    // Create a new PubNub instance
    const pubnubInstance = new PubNub({
      publishKey: "demo",
      subscribeKey: "demo",
      userId: "rn-user-" + Math.floor(Math.random() * 1000)
    });
    
    // Add listener to handle events
    pubnubInstance.addListener({
      // Message handler - called when a message is received
      message: function(event) {
        setMessages(messages => [
          ...messages, 
          { 
            id: event.timetoken || Date.now().toString(),
            message: event.message as ChatMessage
          }
        ]);
        
        // Auto-scroll to bottom when new messages arrive
        setTimeout(() => {
          if (flatListRef.current) {
            flatListRef.current.scrollToEnd({ animated: true });
          }
        }, 100);
      },
      
      // Presence handler - called for join/leave events
      presence: function(event) {
        console.log("Presence event:", event);
        // Skip interval events and your own events
        if (event.action === 'interval' || event.uuid === pubnubInstance.getUserId()) return;
        if (event.action === 'join') {
          // Someone joined the channel
          Alert.alert("User Joined", `${event.uuid} joined the chat`);
        } else if (event.action === 'leave' || event.action === 'timeout') {
          // Someone left the channel
          Alert.alert("User Left", `${event.uuid} left the chat`);
        }
      },
      
      // Status handler - called for connection status changes
      status: function(event) {
        console.log("Status event:", event);
        if (event.category === "PNConnectedCategory") {
          setIsConnected(true);
          setIsLoading(false);
          console.log("Connected to PubNub!");
        } else if (event.category === "PNNetworkIssuesCategory") {
          setIsConnected(false);
          console.log("Connection lost. Attempting to reconnect...");
        } else if (event.category === "PNReconnectedCategory") {
          setIsConnected(true);
          console.log("Reconnected to PubNub!");
        }
      }
    });
    
    // Create a channel entity and subscription
    const channel = pubnubInstance.channel('hello_world');
    const subscription = channel.subscription({
      receivePresenceEvents: true
    });
    
    // Subscribe to the channel
    subscription.subscribe();
    
    // Update state with PubNub instance
    setPubnub(pubnubInstance);
    
    // Clean up on component unmount
    return () => {
      pubnubInstance.removeAllListeners();
      pubnubInstance.destroy();
      console.log("Cleaned up PubNub connection");
    };
  }, []); // Empty dependency array ensures this runs only once on mount

  // Function to publish a message
  const publishMessage = async () => {
    // Don't send empty messages or if not connected
    if (!inputText.trim() || !pubnub || !isConnected) return;
    
    try {
      // Create message object
      const messageObject: ChatMessage = {
        text: inputText,
        sender: pubnub.getUserId(),
        time: new Date().toISOString()
      };
      
      // Publish to PubNub
      const result = await pubnub.publish({
        message: messageObject,
        channel: 'hello_world'
      });
      
      console.log("Message published with timetoken:", result.timetoken);
      
      // Clear input after successful send
      setInputText('');
    } catch (error) {
      console.error("Publish failed:", error);
      Alert.alert(
        "Message Failed", 
        "Could not send your message. Please try again."
      );
    }
  };

  // Render a message item for the FlatList
  const renderMessageItem = ({ item }: { item: MessageItem }) => {
    const isCurrentUser = item.message.sender === pubnub?.getUserId();
    const messageTime = item.message.time 
      ? new Date(item.message.time).toLocaleTimeString([], { 
          hour: '2-digit', 
          minute: '2-digit' 
        }) 
      : '';
      
    return (
      <View style={[
        styles.messageContainer,
        isCurrentUser ? styles.sentMessage : styles.receivedMessage
      ]}>
        <Text style={styles.senderText}>
          {isCurrentUser ? 'You' : (item.message.sender || 'User')}
        </Text>
        <Text style={styles.messageText}>{item.message.text}</Text>
        <Text style={styles.timeText}>{messageTime}</Text>
      </View>
    );
  };

  // Main component render
  return (
    <SafeAreaView style={styles.safeArea}>
      <StatusBar barStyle="dark-content" />
      
      {isLoading ? (
        // Loading screen
        <View style={styles.loadingContainer}>
          <ActivityIndicator size="large" color="#4b0082" />
          <Text style={styles.loadingText}>Connecting to PubNub...</Text>
        </View>
      ) : (
        // Chat UI
        <KeyboardAvoidingView
          behavior={Platform.OS === "ios" ? "padding" : "height"}
          style={styles.container}
          keyboardVerticalOffset={Platform.OS === "ios" ? 90 : 0}
        >
          {/* Header */}
          <View style={styles.header}>
            <Text style={styles.headerText}>PubNub Chat</Text>
            <View style={[
              styles.connectionIndicator,
              isConnected ? styles.connected : styles.disconnected
            ]} />
          </View>
          
          {/* Messages List */}
          <FlatList
            ref={flatListRef}
            data={messages}
            renderItem={renderMessageItem}
            keyExtractor={(item) => item.id}
            style={styles.messagesList}
            contentContainerStyle={styles.messagesContent}
            onContentSizeChange={() => 
              flatListRef.current?.scrollToEnd({ animated: false })
            }
          />
          
          {/* Input Area */}
          <View style={styles.inputContainer}>
            <TextInput
              style={styles.input}
              value={inputText}
              onChangeText={setInputText}
              placeholder="Type a message..."
              placeholderTextColor="#aaa"
              returnKeyType="send"
              onSubmitEditing={publishMessage}
            />
            <TouchableOpacity
              style={[
                styles.sendButton,
                (!inputText.trim() || !isConnected) && styles.sendButtonDisabled
              ]}
              onPress={publishMessage}
              disabled={!inputText.trim() || !isConnected}
            >
              <Text style={styles.sendButtonText}>Send</Text>
            </TouchableOpacity>
          </View>
        </KeyboardAvoidingView>
      )}
    </SafeAreaView>
  );
}

// Component styles
const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  container: {
    flex: 1,
  },
  loadingContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  loadingText: {
    marginTop: 10,
    fontSize: 16,
    color: '#555',
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: '#e0e0e0',
    backgroundColor: '#fff',
  },
  headerText: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#333',
  },
  connectionIndicator: {
    width: 12,
    height: 12,
    borderRadius: 6,
  },
  connected: {
    backgroundColor: '#4CAF50',
  },
  disconnected: {
    backgroundColor: '#F44336',
  },
  messagesList: {
    flex: 1,
    padding: 8,
  },
  messagesContent: {
    paddingBottom: 8,
  },
  messageContainer: {
    padding: 12,
    borderRadius: 16,
    marginVertical: 4,
    maxWidth: '80%',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 1,
    elevation: 1,
  },
  sentMessage: {
    alignSelf: 'flex-end',
    backgroundColor: '#DCF8C6',
    borderBottomRightRadius: 4,
  },
  receivedMessage: {
    alignSelf: 'flex-start',
    backgroundColor: '#fff',
    borderBottomLeftRadius: 4,
  },
  senderText: {
    fontWeight: 'bold',
    fontSize: 13,
    marginBottom: 4,
    color: '#333',
  },
  messageText: {
    fontSize: 15,
    color: '#333',
  },
  timeText: {
    fontSize: 11,
    color: '#999',
    alignSelf: 'flex-end',
    marginTop: 4,
  },
  inputContainer: {
    flexDirection: 'row',
    padding: 12,
    borderTopWidth: 1,
    borderTopColor: '#e0e0e0',
    backgroundColor: '#fff',
  },
  input: {
    flex: 1,
    height: 40,
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 20,
    paddingHorizontal: 16,
    marginRight: 8,
    backgroundColor: '#fff',
    color: '#333',
  },
  sendButton: {
    height: 40,
    paddingHorizontal: 16,
    borderRadius: 20,
    backgroundColor: '#4b0082',
    justifyContent: 'center',
    alignItems: 'center',
  },
  sendButtonDisabled: {
    backgroundColor: '#B39DDB',
  },
  sendButtonText: {
    color: '#fff',
    fontWeight: 'bold',
  },
});
```

To use this example in your React Native project:

1. Create a new React Native project:

   ```bash
   # Using Expo (easiest for beginners)
   npx create-expo-app PubNubChatApp
   cd PubNubChatApp

   # Or using React Native CLI
   npx react-native init PubNubChatApp
   cd PubNubChatApp
   ```

2. Install the PubNub SDK, the URL polyfill that the React Native build of the SDK requires, and the safe area library that the example imports:

   ```bash
   npm install pubnub react-native-url-polyfill react-native-safe-area-context
   ```

3. Replace the content of `App.tsx` with the code above.
4. Run your app:

   ```bash
   # For Expo
   npx expo start

   # For React Native CLI
   npx react-native run-ios
   # or
   npx react-native run-android
   ```

The example includes:

* PubNub initialization with proper cleanup
* Real-time message sending and receiving
* Messages display in a scrollable chat UI
* Connection status indicator
* Presence notifications (when other users join or leave)
* Auto-scrolling message list
* Proper keyboard handling
* Error handling for failed messages
* Loading state while connecting
* Full styling for a production-ready appearance

## Create a subscription

To receive messages on a channel, you need to subscribe to it. PubNub offers an entity-based subscription approach which provides more control and flexibility:

In React Native, we typically subscribe within a useEffect hook:

```tsx
useEffect(() => {
    if (!pubnub) return;
      
    // Create a channel entity
    const channel = pubnub.channel('hello_world');
      
    // Create a subscription
    const subscription = channel.subscription({
        receivePresenceEvents: true
    });
      
    // Subscribe
    subscription.subscribe();
      
    // Clean up on unmount
    return () => {
        // First remove listeners to prevent callbacks during cleanup
        pubnub.removeAllListeners();
          
        // Then unsubscribe if needed
        if (subscription) {
            subscription.unsubscribe();
        }
          
        // Note: Only call destroy() if this component owns the pubnub instance
        // If the pubnub instance is shared, consider only removing listeners
    };
}, [pubnub]);
```

For more information, refer to the [Subscribe](https://www.pubnub.com/docs/sdks/javascript/api-reference/subscribe.md#subscribe) section of the SDK documentation.

## Publish messages

Once you've set up your subscription, you can start publishing messages to channels.

When you publish a message to a channel, PubNub delivers that message to everyone who is subscribed to that channel.

A message can be any type of JavaScript Object Notation (JSON)-serializable data (such as objects, arrays, integers, strings) that is smaller than 32 KiB.

```tsx
// State for the input text
const [inputText, setInputText] = useState('');

// Function to publish a message
const publishMessage = async () => {
    if (!inputText.trim() || !pubnub) return;
      
    try {
        const result = await pubnub.publish({
            message: {
                text: inputText,
                sender: pubnub.getUserId(),
                time: new Date().toISOString()
            },
            channel: 'hello_world'
        });
        console.log("Message published with timetoken:", result.timetoken);
        setInputText(''); // Clear input after sending
    } catch (error) {
        console.error("Publish failed:", error);
        Alert.alert("Error", "Failed to send message");
    }
};

// In your render function
return (
    <View style={styles.container}>
        <TextInput
            value={inputText}
            onChangeText={setInputText}
            placeholder="Type a message..."
            style={styles.input}
        />
        <Button title="Send" onPress={publishMessage} />
    </View>
);
```

## Run the app

Once you've implemented all the previous steps (initialization, listeners, subscription, and publishing), you're ready to run your application:

1. Start your React Native app:

   ```bash
   npm run android
   # or
   npm run ios
   # or
   npm run web
   ```

2. The app should launch on the selected platform.
3. Type a message in the input field and tap **Send**.
4. You should see your message appear in the messages list.
5. To see real-time communication, run the app on another device or simulator.

## Complete example

```tsx
// App.tsx

// Imports
import React, { useState, useEffect, useRef } from 'react';
import {
  StyleSheet,
  View,
  Text,
  TextInput,
  TouchableOpacity,
  FlatList,
  KeyboardAvoidingView,
  Platform,
  StatusBar,
  ActivityIndicator,
  Alert
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import PubNub from 'pubnub';

// Types for the messages
type ChatMessage = {
  text: string;
  sender?: string;
  time?: string;
};

type MessageItem = {
  id: string;
  message: ChatMessage;
};

// Main App Component
export default function App() {
  // State variables
  const [pubnub, setPubnub] = useState<PubNub | null>(null);
  const [messages, setMessages] = useState<MessageItem[]>([]);
  const [inputText, setInputText] = useState('');
  const [isConnected, setIsConnected] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  
  // Reference to the FlatList for auto-scrolling
  const flatListRef = useRef<FlatList>(null);

  // Initialize PubNub on component mount
  useEffect(() => {
    // Create a new PubNub instance
    const pubnubInstance = new PubNub({
      publishKey: "demo",
      subscribeKey: "demo",
      userId: "rn-user-" + Math.floor(Math.random() * 1000)
    });
    
    // Add listener to handle events
    pubnubInstance.addListener({
      // Message handler - called when a message is received
      message: function(event) {
        setMessages(messages => [
          ...messages, 
          { 
            id: event.timetoken || Date.now().toString(),
            message: event.message as ChatMessage
          }
        ]);
        
        // Auto-scroll to bottom when new messages arrive
        setTimeout(() => {
          if (flatListRef.current) {
            flatListRef.current.scrollToEnd({ animated: true });
          }
        }, 100);
      },
      
      // Presence handler - called for join/leave events
      presence: function(event) {
        console.log("Presence event:", event);
        // Skip interval events and your own events
        if (event.action === 'interval' || event.uuid === pubnubInstance.getUserId()) return;
        if (event.action === 'join') {
          // Someone joined the channel
          Alert.alert("User Joined", `${event.uuid} joined the chat`);
        } else if (event.action === 'leave' || event.action === 'timeout') {
          // Someone left the channel
          Alert.alert("User Left", `${event.uuid} left the chat`);
        }
      },
      
      // Status handler - called for connection status changes
      status: function(event) {
        console.log("Status event:", event);
        if (event.category === "PNConnectedCategory") {
          setIsConnected(true);
          setIsLoading(false);
          console.log("Connected to PubNub!");
        } else if (event.category === "PNNetworkIssuesCategory") {
          setIsConnected(false);
          console.log("Connection lost. Attempting to reconnect...");
        } else if (event.category === "PNReconnectedCategory") {
          setIsConnected(true);
          console.log("Reconnected to PubNub!");
        }
      }
    });
    
    // Create a channel entity and subscription
    const channel = pubnubInstance.channel('hello_world');
    const subscription = channel.subscription({
      receivePresenceEvents: true
    });
    
    // Subscribe to the channel
    subscription.subscribe();
    
    // Update state with PubNub instance
    setPubnub(pubnubInstance);
    
    // Clean up on component unmount
    return () => {
      pubnubInstance.removeAllListeners();
      pubnubInstance.destroy();
      console.log("Cleaned up PubNub connection");
    };
  }, []); // Empty dependency array ensures this runs only once on mount

  // Function to publish a message
  const publishMessage = async () => {
    // Don't send empty messages or if not connected
    if (!inputText.trim() || !pubnub || !isConnected) return;
    
    try {
      // Create message object
      const messageObject: ChatMessage = {
        text: inputText,
        sender: pubnub.getUserId(),
        time: new Date().toISOString()
      };
      
      // Publish to PubNub
      const result = await pubnub.publish({
        message: messageObject,
        channel: 'hello_world'
      });
      
      console.log("Message published with timetoken:", result.timetoken);
      
      // Clear input after successful send
      setInputText('');
    } catch (error) {
      console.error("Publish failed:", error);
      Alert.alert(
        "Message Failed", 
        "Could not send your message. Please try again."
      );
    }
  };

  // Render a message item for the FlatList
  const renderMessageItem = ({ item }: { item: MessageItem }) => {
    const isCurrentUser = item.message.sender === pubnub?.getUserId();
    const messageTime = item.message.time 
      ? new Date(item.message.time).toLocaleTimeString([], { 
          hour: '2-digit', 
          minute: '2-digit' 
        }) 
      : '';
      
    return (
      <View style={[
        styles.messageContainer,
        isCurrentUser ? styles.sentMessage : styles.receivedMessage
      ]}>
        <Text style={styles.senderText}>
          {isCurrentUser ? 'You' : (item.message.sender || 'User')}
        </Text>
        <Text style={styles.messageText}>{item.message.text}</Text>
        <Text style={styles.timeText}>{messageTime}</Text>
      </View>
    );
  };

  // Main component render
  return (
    <SafeAreaView style={styles.safeArea}>
      <StatusBar barStyle="dark-content" />
      
      {isLoading ? (
        // Loading screen
        <View style={styles.loadingContainer}>
          <ActivityIndicator size="large" color="#4b0082" />
          <Text style={styles.loadingText}>Connecting to PubNub...</Text>
        </View>
      ) : (
        // Chat UI
        <KeyboardAvoidingView
          behavior={Platform.OS === "ios" ? "padding" : "height"}
          style={styles.container}
          keyboardVerticalOffset={Platform.OS === "ios" ? 90 : 0}
        >
          {/* Header */}
          <View style={styles.header}>
            <Text style={styles.headerText}>PubNub Chat</Text>
            <View style={[
              styles.connectionIndicator,
              isConnected ? styles.connected : styles.disconnected
            ]} />
          </View>
          
          {/* Messages List */}
          <FlatList
            ref={flatListRef}
            data={messages}
            renderItem={renderMessageItem}
            keyExtractor={(item) => item.id}
            style={styles.messagesList}
            contentContainerStyle={styles.messagesContent}
            onContentSizeChange={() => 
              flatListRef.current?.scrollToEnd({ animated: false })
            }
          />
          
          {/* Input Area */}
          <View style={styles.inputContainer}>
            <TextInput
              style={styles.input}
              value={inputText}
              onChangeText={setInputText}
              placeholder="Type a message..."
              placeholderTextColor="#aaa"
              returnKeyType="send"
              onSubmitEditing={publishMessage}
            />
            <TouchableOpacity
              style={[
                styles.sendButton,
                (!inputText.trim() || !isConnected) && styles.sendButtonDisabled
              ]}
              onPress={publishMessage}
              disabled={!inputText.trim() || !isConnected}
            >
              <Text style={styles.sendButtonText}>Send</Text>
            </TouchableOpacity>
          </View>
        </KeyboardAvoidingView>
      )}
    </SafeAreaView>
  );
}

// Component styles
const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  container: {
    flex: 1,
  },
  loadingContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  loadingText: {
    marginTop: 10,
    fontSize: 16,
    color: '#555',
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: '#e0e0e0',
    backgroundColor: '#fff',
  },
  headerText: {
    fontSize: 18,
    fontWeight: 'bold',
    color: '#333',
  },
  connectionIndicator: {
    width: 12,
    height: 12,
    borderRadius: 6,
  },
  connected: {
    backgroundColor: '#4CAF50',
  },
  disconnected: {
    backgroundColor: '#F44336',
  },
  messagesList: {
    flex: 1,
    padding: 8,
  },
  messagesContent: {
    paddingBottom: 8,
  },
  messageContainer: {
    padding: 12,
    borderRadius: 16,
    marginVertical: 4,
    maxWidth: '80%',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 1,
    elevation: 1,
  },
  sentMessage: {
    alignSelf: 'flex-end',
    backgroundColor: '#DCF8C6',
    borderBottomRightRadius: 4,
  },
  receivedMessage: {
    alignSelf: 'flex-start',
    backgroundColor: '#fff',
    borderBottomLeftRadius: 4,
  },
  senderText: {
    fontWeight: 'bold',
    fontSize: 13,
    marginBottom: 4,
    color: '#333',
  },
  messageText: {
    fontSize: 15,
    color: '#333',
  },
  timeText: {
    fontSize: 11,
    color: '#999',
    alignSelf: 'flex-end',
    marginTop: 4,
  },
  inputContainer: {
    flexDirection: 'row',
    padding: 12,
    borderTopWidth: 1,
    borderTopColor: '#e0e0e0',
    backgroundColor: '#fff',
  },
  input: {
    flex: 1,
    height: 40,
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 20,
    paddingHorizontal: 16,
    marginRight: 8,
    backgroundColor: '#fff',
    color: '#333',
  },
  sendButton: {
    height: 40,
    paddingHorizontal: 16,
    borderRadius: 20,
    backgroundColor: '#4b0082',
    justifyContent: 'center',
    alignItems: 'center',
  },
  sendButtonDisabled: {
    backgroundColor: '#B39DDB',
  },
  sendButtonText: {
    color: '#fff',
    fontWeight: 'bold',
  },
});
```

The examples above showcase complete working code that integrates all the concepts covered in this guide:

* PubNub initialization with proper configuration
* Event listener setup for messages and connection status
* Channel subscription using the entity-based approach
* Message publishing with error handling
* User interface components (where applicable)
* Cleanup and resource management

## Next steps

* Pick another path on [Choose your runtime](https://www.pubnub.com/docs/sdks/javascript/choose-runtime.md).
* Try [Presence](https://www.pubnub.com/docs/sdks/javascript/api-reference/presence.md) to track online and offline status.
* Implement [Message Persistence](https://www.pubnub.com/docs/sdks/javascript/api-reference/message-persistence.md) to store and retrieve messages.
* Use [Access Manager](https://www.pubnub.com/docs/sdks/javascript/api-reference/access-manager.md) to secure your channels.
* Explore [Channel Groups](https://www.pubnub.com/docs/sdks/javascript/api-reference/channel-groups.md) to organize your channels.
* Building a chat app? Use the [Chat SDK](https://www.pubnub.com/docs/chat/chat-sdk.md).

Last updated at: 2026-11-09T13:29:01.000Z
