Fully Controlled React Native Mentions Component

Fully Controlled React Native Mentions Component

react-native-controlled-mentions Pretty simple and fully controlled mention input. It can:

react-native-controlled-mentions

Pretty simple and fully controlled mention input. It can:

  • Gracefully render formatted mentions directly in RN TextInput component
  • Support for different mention types (@user mentions, #hashtags, etc)
  • Use value/onChange as in usual TextInput props
  • Completely typed (written on TypeScript)
  • No need for native libraries

In addition, you can add custom styling for a regex pattern (like URLs) using the optimized recursive function for parsing the value.

Demo

Try it on Expo Snack: https://snack.expo.io/@dabakovich/mentionsapp

Getting started

Install the library using either Yarn:

yarn add react-native-controlled-mentions

or npm:

npm install --save react-native-controlled-mentions

Usage

Import the MentionInput component:

import { MentionInput } from 'react-native-controlled-mentions'

Replace your TextInput by MentionInput component and add the partTypes property where you can define what mention or pattern types you want to support. It takes an array of PartType objects.

<MentionInput
  value={value}
  onChange={setValue}

  partTypes={[
    {
      trigger: '@', // Should be a single character like '@' or '#'
      renderSuggestions,
      textStyle: {fontWeight: 'bold', color: 'blue'}, // The mention style in the input
    },
  ]}
/>

Define your renderSuggestions functional component that receive MentionSuggestionsProps:

const suggestions = [
  {id: '1', name: 'David Tabaka'},
  {id: '2', name: 'Mary'},
  {id: '3', name: 'Tony'},
  {id: '4', name: 'Mike'},
  {id: '5', name: 'Grey'},
];

const renderSuggestions: FC<MentionSuggestionsProps> = ({keyword, onSuggestionPress}) => {
  if (keyword == null) {
    return null;
  }

  return (
    <View>
      {suggestions
        .filter(one => one.name.toLocaleLowerCase().includes(keyword.toLocaleLowerCase()))
        .map(one => (
          <Pressable
            key={one.id}
            onPress={() => onSuggestionPress(one)}

            style={{padding: 12}}
          >
            <Text>{one.name}</Text>
          </Pressable>
        ))
      }
    </View>
  );
};

You're done!

The whole example is in the /example folder.

API

MentionInput component props

Property name Description Type Required Default
value The same as in TextInput string true
onChange The same as in TextInput (value: string) => void true
partTypes Declare what part types you want to support (mentions, hashtags, urls) PartType[] false []
inputRef Reference to the TextInput component inside MentionInput RefTextInput> false
containerStyle Style to the MentionInput's root component StyleProp<TextStyle> false
...textInputProps Other text input props TextInputProps false

PartType type

MentionPartType | PatternPartType

MentionPartType type props

Property name Description Type Required Default
trigger Character that will trigger current mention type string true
renderSuggestions Renderer for mention suggestions component (props: MentionSuggestionsProps) => ReactNode false
isInsertSpaceAfterMention Should we add a space after selected mentions if the mention is at the end of row boolean false false
textStyle Text style for mentions in TextInput StyleProp false
getPlainString Function for generating custom mention text in text input (mention: MentionData) => string false

PatternPartType type props

Property name Description Type Required Default
pattern RegExp for parsing a pattern, should include global flag RegExp true
textStyle Text style for pattern in TextInput StyleProp false

MentionSuggestionsProps type props

keyword: string | undefined

Keyword that will provide string between trigger character (e.g. '@') and cursor.

If the cursor is not tracking any mention typing the keyword will be undefined.

Examples where @name is just plain text yet, not mention and | is cursor position:

'|abc @name dfg' - keyword is undefined
'abc @| dfg' - keyword is ''
'abc @name| dfg' - keyword is 'name'
'abc @na|me dfg' - keyword is 'na'
'abc @|name dfg' - keyword is against ''
'abc @name |dfg' - keyword is against undefined

onSuggestionPress: (suggestion: Suggestion) => void

You should call that callback when user selects any suggestion.

Suggestion type props

id: string

Unique id for each suggestion.

name: string

Name that will be shown in MentionInput when user will select the suggestion.

MentionData type props

For example, we have that mention value @[David Tabaka](123). Then after parsing that string by mentionRegEx we will get next properties:

original: string

The whole mention value string - @[David Tabaka](123)

trigger: string

The extracted trigger - @

name: string

The extracted name - David Tabaka

id: string

The extracted id - 123

mentionRegEx

/(?<original>(?<trigger>.)\[(?<name>([^[]*))]\((?<id>([\d\w-]*))\))/gi;

Parsing MentionInput's value

You can import RegEx that is using in the component and then extract all your mentions from MentionInput's value using your own logic.

import { mentionRegEx } from 'react-native-controlled-mentions';

Or you can use replaceMentionValues helper to replace all mentions from MentionInput's input using your replacer function that receives MentionData type and returns string.

import { replaceMentionValues } from 'react-native-controlled-mentions';

const value = 'Hello @[David Tabaka](5)! How are you?';

console.log(replaceMentionValues(value, ({id}) => `@${id}`)); // Hello @5! How are you?
console.log(replaceMentionValues(value, ({name}) => `@${name}`)); // Hello @David Tabaka! How are you?

Rendering MentionInput's value

If you want to parse and render your value somewhere else you can use parseValue tool which gives you array of parts and then use your own part renderer to resolve this issue.

Here is an example:

import {
  Part,
  PartType,
  parseValue,
  isMentionPartType,
} from 'react-native-controlled-mentions';

/**
 * Part renderer
 * 
 * @param part
 * @param index
 */
const renderPart = (
  part: Part,
  index: number,
) => {
  // Just plain text
  if (!part.partType) {
    return <Text key={index}>{part.text}</Text>;
  }

  // Mention type part
  if (isMentionPartType(part.partType)) {
    return (
      <Text
        key={`${index}-${part.data?.trigger}`}
        style={part.partType.textStyle}
        onPress={() => console.log('Pressed', part.data)}
      >
        {part.text}
      </Text>
    );
  }

  // Other styled part types
  return (
    <Text
      key={`${index}-pattern`}
      style={part.partType.textStyle}
    >
      {part.text}
    </Text>
  );
};

/**
 * Value renderer. Parsing value to parts array and then mapping the array using 'renderPart'
 * 
 * @param value - value from MentionInput
 * @param partTypes - the part types array that you providing to MentionInput
 */
const renderValue: FC = (
  value: string,
  partTypes: PartType[],
) => {
  const {parts} = parseValue(value, partTypes);

  return <Text>{parts.map(renderPart)}</Text>;
};

To Do

  • Add support for different text formatting (e.g. URLs)
  • Add more customizations DONE
  • Add ability to handle few mention types ("#", "@" etc) DONE

Known issues

  • Mention name regex accepts white spaces (e.g. {name: ' ', value: 1})
  • Keyboard auto-correction not working if suggested word has the same length FIXED
  • Text becomes transparent when setting custom font size in TextInput FIXED

Download Details:

Author: dabakovich

Demo: https://snack.expo.io/@dabakovich/mentionsapp

Source Code: https://github.com/dabakovich/react-native-controlled-mentions

react-native react mobile-apps

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

How native is React Native? | React Native vs Native App Development

Article covers: How native is react native?, React Native vs (Ionic, Cordova), Similarities and difference between React Native and Native App Development.

React Native Mobile App Development

Skenix is providing React Native Development Services with qualified React Native App Developers. Get the best React Native App Development Services.

How React Native Is Shaping Mobile App Development

Are you a mobile app developer looking for more efficient tools for your projects? Mobile app development is getting tougher and tougher as the market continues to grow. As a developer, you need to develop Apps which meet the demands of your users. To achieve this, adopt the right tools, like the React Native development framework.

Top React Native Mobile App Development Companies in USA

Looking for top React Native mobile app development company in USA for Startups & Enterprise? Find out the top list of React Native mobile app development company in USA.

Which is the best React Native app development company in New York?

Hire top react native app development company in New York to build and develop custom react native mobile apps for Android & iOS with the latest features.