Mention

Mention component.

When To Use#

When need to mention someone or something.

Examples

@afc163

Basic usage.

expand codeexpand code
import { Mention } from 'antd';

const { toString, toContentState } = Mention;

function onChange(contentState) {
  console.log(toString(contentState));
}

function onSelect(suggestion) {
  console.log('onSelect', suggestion);
}

ReactDOM.render(
  <Mention
    style={{ width: '100%' }}
    onChange={onChange}
    defaultValue={toContentState('@afc163')}
    suggestions={['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご']}
    onSelect={onSelect}
  />,
  mountNode
);

async

expand codeexpand code
import { Mention } from 'antd';

const users = ['afc163', 'benjycui', 'yiminghe', 'jljsj33', 'dqaria', 'RaoHai'];

class AsyncMention extends React.Component {
  state = {
    suggestions: [],
    loading: false,
  }

  fetchSuggestions = (value, callback) => {
    setTimeout(() => {
      callback(users.filter(item => item.indexOf(value) !== -1));
    }, 500);
  }

  onSearchChange = (value) => {
    this.fetchSuggestions(value, (suggestions) => {
      this.setState({
        suggestions,
        loading: false,
      });
    });
    this.setState({
      loading: true,
    });
  }

  render() {
    const { suggestions, loading } = this.state;
    return (
      <Mention
        style={{ width: '100%' }}
        loading={loading}
        suggestions={suggestions}
        onSearchChange={this.onSearchChange}
      />
    );
  }
}

ReactDOM.render(<AsyncMention />, mountNode);

Customize suggestions.

expand codeexpand code
import { Mention, Avatar } from 'antd';

const Nav = Mention.Nav;

const webFrameworks = [
  { name: 'React', type: 'JavaScript', icon: 'https://zos.alipayobjects.com/rmsportal/LFIeMPzdLcLnEUe.svg' },
  { name: 'Angular', type: 'JavaScript', icon: 'https://zos.alipayobjects.com/rmsportal/PJTbxSvzYWjDZnJ.png' },
  { name: 'Dva', type: 'Javascript', icon: 'https://zos.alipayobjects.com/rmsportal/EYPwSeEJKxDtVxI.png' },
  { name: 'Flask', type: 'Python', icon: 'https://zos.alipayobjects.com/rmsportal/xaypBUijfnpAlXE.png' },
];

class CustomNavMention extends React.Component {
  state = {
    suggestions: [],
  }

  onSearchChange = (value) => {
    const searchValue = value.toLowerCase();
    const filtered = webFrameworks.filter(item => item.name.toLowerCase().indexOf(searchValue) !== -1);
    const suggestions = filtered.map(suggestion => (
      <Nav
        value={suggestion.name}
        data={suggestion}
        disabled={suggestion.disabled}
      >
        <Avatar
          src={suggestion.icon}
          size="small"
          style={{
            width: 14, height: 14, marginRight: 8, top: -1, position: 'relative',
          }}
        />
        {suggestion.name} - {suggestion.type}
      </Nav>
    ));
    this.setState({ suggestions });
  }

  render() {
    const { suggestions } = this.state;
    return (
      <Mention
        style={{ width: '100%' }}
        suggestions={suggestions}
        onSearchChange={this.onSearchChange}
      />
    );
  }
}

ReactDOM.render(<CustomNavMention />, mountNode);
@afc163
   

Controlled mode, for example, to work with Form.

expand codeexpand code
import { Mention, Form, Button } from 'antd';

const { toContentState, getMentions } = Mention;
const FormItem = Form.Item;

class App extends React.Component {
  state = {
    initValue: toContentState('@afc163'),
  }

  handleReset = (e) => {
    e.preventDefault();
    this.props.form.resetFields();
  }

  handleSubmit = (e) => {
    e.preventDefault();
    this.props.form.validateFields((errors, values) => {
      if (errors) {
        console.log('Errors in the form!!!');
        return;
      }
      console.log('Submit!!!');
      console.log(values);
    });
  }

  checkMention = (rule, value, callback) => {
    const { getFieldValue } = this.props.form;
    const mentions = getMentions(getFieldValue('mention'));
    if (mentions.length < 2) {
      callback(new Error('More than one must be selected!'));
    } else {
      callback();
    }
  }

  render() {
    const { getFieldDecorator, getFieldValue } = this.props.form;
    console.log('>> render', getFieldValue('mention') === this.state.initValue);
    return (
      <Form layout="horizontal">
        <FormItem
          id="control-mention"
          label="Top coders"
          labelCol={{ span: 6 }}
          wrapperCol={{ span: 16 }}
        >
          {getFieldDecorator('mention', {
            rules: [
              { validator: this.checkMention },
            ],
            initialValue: this.state.initValue,
          })(
            <Mention
              suggestions={['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご']}
            />
          )}
        </FormItem>
        <FormItem wrapperCol={{ span: 14, offset: 6 }}>
          <Button type="primary" onClick={this.handleSubmit}>Submit</Button>
          &nbsp;&nbsp;&nbsp;
          <Button onClick={this.handleReset}>Reset</Button>
        </FormItem>
      </Form>
    );
  }
}

const FormDemo = Form.create()(App);

ReactDOM.render(<FormDemo />, mountNode);

To set the container of the suggestion.

expand codeexpand code
import { Mention, Popover, Button } from 'antd';

const { toString, toContentState } = Mention;

function onChange(editorState) {
  console.log(toString(editorState));
}

function onSelect(suggestion) {
  console.log('onSelect', suggestion);
}

class PopoverContainer extends React.Component {
  getSuggestionContainer = () => this.popover.getPopupDomNode()

  visibleChange = (visible) => {
    if (visible && this.mention) {
      this.mention.focus();
    }
  }

  render() {
    const mention = (
      <Mention
        ref={ele => this.mention = ele}
        style={{ width: '100%' }}
        onChange={onChange}
        defaultValue={toContentState('@afc163')}
        suggestions={['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご']}
        onSelect={onSelect}
        getSuggestionContainer={this.getSuggestionContainer}
      />
    );
    return (
      <Popover
        trigger="click"
        content={mention}
        title="Title"
        ref={popover => this.popover = popover}
        onVisibleChange={this.visibleChange}
      >
        <Button type="primary">Click Me</Button>
      </Popover>
    );
  }
}

ReactDOM.render(<PopoverContainer />, mountNode);
input @ to mention people, # to mention tag

Customize Trigger Token by prefix props. Default to @, Array<string> also supported.

expand codeexpand code
import { Mention } from 'antd';

const { toString } = Mention;

function onChange(editorState) {
  console.log(toString(editorState));
}

function onSelect(suggestion) {
  console.log('onSelect', suggestion);
}

const users = ['afc163', 'benjycui', 'yiminghe', 'jljsj33', 'dqaria', 'RaoHai'];
const tags = ['1.0', '2.0', '3.0'];

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      suggestions: [],
    };
  }

  onSearchChange = (value, trigger) => {
    console.log('onSearchChange', value, trigger);
    const dataSource = trigger === '@' ? users : tags;
    this.setState({
      suggestions: dataSource.filter(item => item.indexOf(value) !== -1),
    });
  }

  render() {
    return (
      <Mention
        style={{ width: '100%' }}
        onChange={onChange}
        placeholder="input @ to mention people, # to mention tag"
        prefix={['@', '#']}
        onSearchChange={this.onSearchChange}
        suggestions={this.state.suggestions}
        onSelect={onSelect}
      />
    );
  }
}

ReactDOM.render(
  <App />,
  mountNode
);

Change the suggestions placement.

expand codeexpand code
import { Mention } from 'antd';

const { toString } = Mention;

function onChange(contentState) {
  console.log(toString(contentState));
}

function onSelect(suggestion) {
  console.log('onSelect', suggestion);
}

ReactDOM.render(
  <Mention
    style={{ width: '100%' }}
    onChange={onChange}
    suggestions={['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご']}
    onSelect={onSelect}
    placement="top"
  />,
  mountNode
);
@someone

Customize suggestions.

expand codeexpand code
import { Mention } from 'antd';

const Nav = Mention.Nav;

const webFrameworks = [
  { name: 'React', type: 'JavaScript' },
  { name: 'Angular', type: 'JavaScript' },
  { name: 'Laravel', type: 'PHP', disabled: true },
  { name: 'Flask', type: 'Python' },
  { name: 'Django', type: 'Python' },
];

function onSelect(suggestion, data) {
  console.log('onSelect', suggestion, data);
}

class CustomNavMention extends React.Component {
  state = {
    suggestions: [],
  }

  onSearchChange = (value) => {
    const searchValue = value.toLowerCase();
    const filtered = webFrameworks.filter(item => item.name.toLowerCase().indexOf(searchValue) !== -1);
    const suggestions = filtered.map(suggestion => (
      <Nav
        value={suggestion.name}
        data={suggestion}
      >
        <span>{suggestion.name} - {suggestion.type}</span>
      </Nav>
    ));
    this.setState({ suggestions });
  }

  render() {
    const { suggestions } = this.state;
    return (
      <Mention
        placeholder="@someone"
        style={{ width: '100%' }}
        suggestions={suggestions}
        onSearchChange={this.onSearchChange}
        onSelect={onSelect}
      />
    );
  }
}

ReactDOM.render(<CustomNavMention />, mountNode);
@afc163

Controlled mode.

expand codeexpand code
import { Mention } from 'antd';

const { toContentState } = Mention;

class App extends React.Component {
  state = {
    value: toContentState('@afc163'),
  }

  componentDidMount() {
    this.mention.focus();
  }

  handleChange = (editorState) => {
    this.setState({
      value: editorState,
    });
  }

  render() {
    return (
      <Mention
        ref={ele => this.mention = ele}
        suggestions={['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご']}
        value={this.state.value}
        onChange={this.handleChange}
      />
    );
  }
}

ReactDOM.render(<App />, mountNode);

Multi lines mode.

expand codeexpand code
import { Mention } from 'antd';

const { toString } = Mention;

function onChange(editorState) {
  console.log(toString(editorState));
}

ReactDOM.render(
  <Mention
    style={{ width: '100%', height: 100 }}
    onChange={onChange}
    suggestions={['afc163', 'benjycui', 'yiminghe', 'jljsj33', 'dqaria', 'RaoHai']}
    multiLines
  />,
  mountNode
);
this is disabled Mention

this is readOnly Mention

Configurate disabled and readOnly.

expand codeexpand code
import { Mention } from 'antd';

const { toString } = Mention;

function onChange(editorState) {
  console.log(toString(editorState));
}

const users = ['afc163', 'benjycui', 'yiminghe', 'jljsj33', 'dqaria', 'RaoHai'];

function App() {
  return (
    <div>
      <div style={{ marginBottom: 10 }}>
        <Mention
          style={{ width: '100%' }}
          onChange={onChange}
          placeholder="this is disabled Mention"
          suggestions={users}
          disabled
        />
      </div>
      <Mention
        style={{ width: '100%' }}
        onChange={onChange}
        placeholder="this is readOnly Mention"
        suggestions={users}
        readOnly
      />
    </div>
  );
}


ReactDOM.render(
  <App />,
  mountNode
);

API#

<Mention
  onChange={onChange}
  suggestions={['afc163', 'benjycui', 'yiminghe', 'jljsj33', 'dqaria', 'RaoHai']}
/>

Mention API#

APIDescriptionType
getMentionsget mentioned people in current contentStateFunction(ContentState: contentState): string[]
toContentStateconvert string to ContentStateFunction(value: string): ContentState
toStringconvert ContentState to stringFunction(contentState: ContentState): string

Mention#

PropertyDescriptionTypeDefault
autoFocusget focus when component mountedbooleanfalse
defaultValuedefault valueContentState, you can use Mention.toContentState to convert text to ContentStatenull
disabledTell if the input is disabled.booleanfalse
getSuggestionContainerrendered to the root of the menu. Default rendered to the body dom. If gets any problem of the menu while scrolling. Try to make the root the dom scrolled, and make it position relative.function() => document.body
loadingloading modebooleanfalse
multiLinesmultilines modebooleanfalse
notFoundContentsuggestion when suggestions emptystring'无匹配结果,轻敲空格完成输入'
placeholderplaceholder of inputstringnull
placementThe position of the suggestion relative to the target, which can be one of top and bottomstring'bottom'.
prefixcharacter which will trigger Mention to show mention liststring or Array'@'
readOnlyTell if the input is readonly.booleanfalse
suggestionssuggestion contentArray<string|Mention.Nav>[]
suggestionStylestyle of suggestion containerobject{}
valuecore state of mentionContentStatenull
onBlurCallback function called when mention component blurfunction(e)null
onChangeCallback function called when content of input changesfunction(contentState: ContentState)null
onFocusCallback function called when mention component get focusfunctione)null
onSearchChangeCallback function called when search content changesfunction(value:string, trigger: string)[]
onSelectCallback function called when select from suggestionsfunction(suggestion: string, data?: any)null

Mention methods#

NameDescription
blur()remove focus
focus()get focus
PropertyDescriptionTypeDefault
childrensuggestion contentobject{}
valuevalue of suggestion,the value will insert into input filed while selectedstring""