Skip to main content
This component is iOS-only. It will not work on Android or other platforms.
A component which enables customization of the keyboard input accessory view. The input accessory view is displayed above the keyboard whenever a TextInput has focus. This component can be used to create custom toolbars. To use this component, wrap your custom toolbar with the InputAccessoryView component and set a nativeID. Then, pass that nativeID as the inputAccessoryViewID of whatever TextInput you desire.

Example

import React, { useState } from 'react';
import {
  Button,
  InputAccessoryView,
  ScrollView,
  TextInput,
  StyleSheet,
} from 'react-native';

const App = () => {
  const inputAccessoryViewID = 'uniqueID';
  const [text, setText] = useState('Placeholder Text');

  return (
    <>
      <ScrollView keyboardDismissMode="interactive">
        <TextInput
          style={styles.input}
          inputAccessoryViewID={inputAccessoryViewID}
          onChangeText={setText}
          value={text}
        />
      </ScrollView>
      <InputAccessoryView nativeID={inputAccessoryViewID}>
        <Button onPress={() => setText('Placeholder Text')} title="Reset Text" />
      </InputAccessoryView>
    </>
  );
};

const styles = StyleSheet.create({
  input: {
    padding: 16,
    marginTop: 50,
    borderWidth: 1,
    borderColor: '#ccc',
  },
});

export default App;

Props

nativeID

Type: string An ID which is used to associate this InputAccessoryView to specified TextInput(s). To link the InputAccessoryView to a TextInput, set the TextInput’s inputAccessoryViewID prop to match this nativeID.
const inputAccessoryViewID = 'toolbar';

<TextInput inputAccessoryViewID={inputAccessoryViewID} />
<InputAccessoryView nativeID={inputAccessoryViewID}>
  {/* Your custom toolbar */}
</InputAccessoryView>

backgroundColor

Type: ColorValue The background color of the input accessory view.
<InputAccessoryView nativeID="toolbar" backgroundColor="#f0f0f0">
  {/* Your custom toolbar */}
</InputAccessoryView>

style

Type: ViewStyle Style for the InputAccessoryView container.
<InputAccessoryView
  nativeID="toolbar"
  style={{
    backgroundColor: '#ffffff',
    borderTopWidth: 1,
    borderTopColor: '#cccccc',
  }}>
  {/* Your custom toolbar */}
</InputAccessoryView>

children

Type: React.ReactNode The content to display in the input accessory view. This is typically a toolbar with buttons or other controls.

Sticky TextInput

This component can also be used to create sticky text inputs (text inputs which are anchored to the top of the keyboard). To do this, wrap a TextInput with the InputAccessoryView component, and don’t set a nativeID.
import React, { useState } from 'react';
import { InputAccessoryView, TextInput, StyleSheet } from 'react-native';

const App = () => {
  const [text, setText] = useState('');

  return (
    <InputAccessoryView>
      <TextInput
        style={styles.input}
        value={text}
        onChangeText={setText}
        placeholder="Type here..."
      />
    </InputAccessoryView>
  );
};

const styles = StyleSheet.create({
  input: {
    backgroundColor: '#f0f0f0',
    padding: 10,
    margin: 10,
    borderRadius: 5,
  },
});

export default App;

Complete Example

import React, { useState } from 'react';
import {
  View,
  TextInput,
  InputAccessoryView,
  Button,
  ScrollView,
  Text,
  StyleSheet,
} from 'react-native';

const App = () => {
  const inputAccessoryViewID = 'customToolbar';
  const [text, setText] = useState('');
  const [messages, setMessages] = useState([]);

  const sendMessage = () => {
    if (text.trim()) {
      setMessages([...messages, text]);
      setText('');
    }
  };

  const addQuickReply = (reply) => {
    setText(reply);
  };

  return (
    <View style={styles.container}>
      <ScrollView style={styles.messagesContainer}>
        {messages.map((message, index) => (
          <View key={index} style={styles.message}>
            <Text>{message}</Text>
          </View>
        ))}
      </ScrollView>

      <TextInput
        style={styles.input}
        inputAccessoryViewID={inputAccessoryViewID}
        placeholder="Type a message..."
        value={text}
        onChangeText={setText}
        multiline
      />

      <InputAccessoryView
        nativeID={inputAccessoryViewID}
        backgroundColor="#f8f8f8">
        <View style={styles.toolbar}>
          <View style={styles.quickReplies}>
            <Button
              title="👍"
              onPress={() => addQuickReply('👍')}
              color="#007AFF"
            />
            <Button
              title="Thanks!"
              onPress={() => addQuickReply('Thanks!')}
              color="#007AFF"
            />
            <Button
              title="OK"
              onPress={() => addQuickReply('OK')}
              color="#007AFF"
            />
          </View>
          <Button title="Send" onPress={sendMessage} color="#007AFF" />
        </View>
      </InputAccessoryView>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  messagesContainer: {
    flex: 1,
    padding: 10,
  },
  message: {
    backgroundColor: '#e1f5fe',
    padding: 10,
    borderRadius: 8,
    marginBottom: 10,
    alignSelf: 'flex-start',
  },
  input: {
    borderTopWidth: 1,
    borderTopColor: '#ccc',
    padding: 10,
    minHeight: 50,
    maxHeight: 100,
  },
  toolbar: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 10,
    borderTopWidth: 1,
    borderTopColor: '#ccc',
  },
  quickReplies: {
    flexDirection: 'row',
    gap: 8,
  },
});

export default App;

Custom Toolbar Example

import React, { useState } from 'react';
import {
  View,
  TextInput,
  InputAccessoryView,
  TouchableOpacity,
  Text,
  ScrollView,
  StyleSheet,
} from 'react-native';

const App = () => {
  const inputAccessoryViewID = 'formatToolbar';
  const [text, setText] = useState('');

  const insertFormatting = (prefix, suffix = '') => {
    setText(text + prefix + suffix);
  };

  return (
    <View style={styles.container}>
      <ScrollView style={styles.content}>
        <Text style={styles.preview}>{text}</Text>
      </ScrollView>

      <TextInput
        style={styles.input}
        inputAccessoryViewID={inputAccessoryViewID}
        placeholder="Type with formatting..."
        value={text}
        onChangeText={setText}
        multiline
      />

      <InputAccessoryView
        nativeID={inputAccessoryViewID}
        backgroundColor="#ffffff"
        style={styles.accessoryView}>
        <ScrollView horizontal showsHorizontalScrollIndicator={false}>
          <View style={styles.toolbar}>
            <TouchableOpacity
              style={styles.button}
              onPress={() => insertFormatting('**', '**')}>
              <Text style={styles.buttonText}>Bold</Text>
            </TouchableOpacity>
            <TouchableOpacity
              style={styles.button}
              onPress={() => insertFormatting('_', '_')}>
              <Text style={styles.buttonText}>Italic</Text>
            </TouchableOpacity>
            <TouchableOpacity
              style={styles.button}
              onPress={() => insertFormatting('# ')}>
              <Text style={styles.buttonText}>H1</Text>
            </TouchableOpacity>
            <TouchableOpacity
              style={styles.button}
              onPress={() => insertFormatting('- ')}>
              <Text style={styles.buttonText}>List</Text>
            </TouchableOpacity>
            <TouchableOpacity
              style={styles.button}
              onPress={() => insertFormatting('`', '`')}>
              <Text style={styles.buttonText}>Code</Text>
            </TouchableOpacity>
            <TouchableOpacity
              style={styles.button}
              onPress={() => setText('')}>
              <Text style={[styles.buttonText, styles.clearButton]}>Clear</Text>
            </TouchableOpacity>
          </View>
        </ScrollView>
      </InputAccessoryView>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  content: {
    flex: 1,
    padding: 20,
  },
  preview: {
    fontSize: 16,
    lineHeight: 24,
  },
  input: {
    borderTopWidth: 1,
    borderTopColor: '#e0e0e0',
    padding: 15,
    fontSize: 16,
    minHeight: 60,
  },
  accessoryView: {
    borderTopWidth: 1,
    borderTopColor: '#e0e0e0',
  },
  toolbar: {
    flexDirection: 'row',
    padding: 8,
    gap: 8,
  },
  button: {
    paddingVertical: 8,
    paddingHorizontal: 16,
    backgroundColor: '#007AFF',
    borderRadius: 8,
    justifyContent: 'center',
    alignItems: 'center',
  },
  buttonText: {
    color: '#ffffff',
    fontSize: 14,
    fontWeight: '600',
  },
  clearButton: {
    color: '#ff3b30',
  },
});

export default App;

Tips

  • The nativeID must be unique within your application.
  • Multiple TextInputs can share the same inputAccessoryViewID to use the same toolbar.
  • The InputAccessoryView will automatically appear and disappear with the keyboard.
  • Use keyboardDismissMode="interactive" on ScrollView to allow dismissing the keyboard by dragging.
  • The InputAccessoryView respects safe area insets automatically.

Build docs developers (and LLMs) love