Transfer

Double column transfer choice box.

When To Use#

Transfer the elements between two columns in an intuitive and efficient way.

One or more elements can be selected from either column, one click on the proper 'direction' button, and the transfer is done. The left column is considered the 'source' and the right column is considered the 'target'. As you can see in the API description, these names are reflected in.

Examples

14 itemsSource
Not Found
6 itemsTarget
Not Found

The most basic usage of Transfer involves providing the source data and target keys arrays, plus the rendering and some callback functions.

import { Transfer } from 'antd';

const mockData = [];
for (let i = 0; i < 20; i++) {
  mockData.push({
    key: i.toString(),
    title: `content${i + 1}`,
    description: `description of content${i + 1}`,
    disabled: i % 3 < 1,
  });
}

const targetKeys = mockData
        .filter(item => +item.key % 3 > 1)
        .map(item => item.key);

class App extends React.Component {
  state = {
    targetKeys,
    selectedKeys: [],
  }

  handleChange = (nextTargetKeys, direction, moveKeys) => {
    this.setState({ targetKeys: nextTargetKeys });

    console.log('targetKeys: ', targetKeys);
    console.log('direction: ', direction);
    console.log('moveKeys: ', moveKeys);
  }

  handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
    this.setState({ selectedKeys: [...sourceSelectedKeys, ...targetSelectedKeys] });

    console.log('sourceSelectedKeys: ', sourceSelectedKeys);
    console.log('targetSelectedKeys: ', targetSelectedKeys);
  }

  handleScroll = (direction, e) => {
    console.log('direction:', direction);
    console.log('target:', e.target);
  }

  render() {
    const state = this.state;
    return (
      <Transfer
        dataSource={mockData}
        titles={['Source', 'Target']}
        targetKeys={state.targetKeys}
        selectedKeys={state.selectedKeys}
        onChange={this.handleChange}
        onSelectChange={this.handleSelectChange}
        onScroll={this.handleScroll}
        render={item => item.title}
      />
    );
  }
}

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

Advanced Usage of Transfer.

You can customize the labels of the transfer buttons, the width and height of the columns, and what should be displayed in the footer.

import { Transfer, Button } from 'antd';

class App extends React.Component {
  state = {
    mockData: [],
    targetKeys: [],
  }
  componentDidMount() {
    this.getMock();
  }
  getMock = () => {
    const targetKeys = [];
    const mockData = [];
    for (let i = 0; i < 20; i++) {
      const data = {
        key: i.toString(),
        title: `content${i + 1}`,
        description: `description of content${i + 1}`,
        chosen: Math.random() * 2 > 1,
      };
      if (data.chosen) {
        targetKeys.push(data.key);
      }
      mockData.push(data);
    }
    this.setState({ mockData, targetKeys });
  }
  handleChange = (targetKeys) => {
    this.setState({ targetKeys });
  }
  renderFooter = () => {
    return (
      <Button
        size="small"
        style={{ float: 'right', margin: 5 }}
        onClick={this.getMock}
      >
        reload
      </Button>
    );
  }
  render() {
    return (
      <Transfer
        dataSource={this.state.mockData}
        showSearch
        listStyle={{
          width: 250,
          height: 300,
        }}
        operations={['to right', 'to left']}
        targetKeys={this.state.targetKeys}
        onChange={this.handleChange}
        render={item => `${item.title}-${item.description}`}
        footer={this.renderFooter}
      />
    );
  }
}

ReactDOM.render(<App />, mountNode);
0 item
    Not Found
    0 item
      Not Found

      Custom each Transfer Item, and in this way you can render a complex datasource.

      import { Transfer } from 'antd';
      
      class App extends React.Component {
        state = {
          mockData: [],
          targetKeys: [],
        }
        componentDidMount() {
          this.getMock();
        }
        getMock = () => {
          const targetKeys = [];
          const mockData = [];
          for (let i = 0; i < 20; i++) {
            const data = {
              key: i.toString(),
              title: `content${i + 1}`,
              description: `description of content${i + 1}`,
              chosen: Math.random() * 2 > 1,
            };
            if (data.chosen) {
              targetKeys.push(data.key);
            }
            mockData.push(data);
          }
          this.setState({ mockData, targetKeys });
        }
        handleChange = (targetKeys, direction, moveKeys) => {
          console.log(targetKeys, direction, moveKeys);
          this.setState({ targetKeys });
        }
        renderItem = (item) => {
          const customLabel = (
            <span className="custom-item">
              {item.title} - {item.description}
            </span>
          );
      
          return {
            label: customLabel,  // for displayed item
            value: item.title,   // for title and filter matching
          };
        }
        render() {
          return (
            <Transfer
              dataSource={this.state.mockData}
              listStyle={{
                width: 300,
                height: 300,
              }}
              targetKeys={this.state.targetKeys}
              onChange={this.handleChange}
              render={this.renderItem}
            />
          );
        }
      }
      
      ReactDOM.render(<App />, mountNode);

      API#

      PropertyDescriptionTypeDefault
      dataSourceUsed for setting the source data. The elements that are part of this array will be present the left column. Except the elements whose keys are included in targetKeys prop.TransferItem[][]
      renderThe function to generate the item shown on a column. Based on an record (element of the dataSource array), this function should return a React element which is generated from that record.Function(record)
      targetKeysA set of keys of elements that are listed on the right column.string[][]
      selectedKeysA set of keys of selected items.string[][]
      onChangeA callback function that is executed when the transfer between columns is complete.(targetKeys, direction, moveKeys): void
      onSelectChangeA callback function which is executed when selected items are changed.(sourceSelectedKeys, targetSelectedKeys): void
      onScrollA callback function which is executed when scroll options list(direction, event): void
      listStyleA custom CSS style used for rendering the transfer columns.object
      classNameA custom CSS class.string'', ''
      titlesA set of titles that are sorted from left to right.string[]-
      operationsA set of operations that are sorted from bottom to top.string[]'>', '<'
      showSearchIf included, a search box is shown on each column.booleanfalse
      filterOptionA function to determine whether an item should show in search result list(inputValue, option): boolean
      searchPlaceholderThe hint text of the search box.string'Search here'
      notFoundContentText to display when a column is empty.string|ReactNode'The list is empty'
      footerA function used for rendering the footer.(props): ReactNode
      lazyproperty of react-lazy-load for lazy rendering itemsobject{ height: 32, offset: 32 }
      onSearchChangeA callback function which is executed when search field are changed(direction: 'left'|'right', event: Event): void-

      Warning#

      According the standard of React, the key should always be supplied directly to the elements in the array. In Transfer, the keys should be set on the elements included in dataSource array. By default, key property is used as an unique identifier.

      If there's no key in your data, you should use rowKey to specify the key that will be used for uniquely identify each element.

      // eg. your primary key is `uid`
      return <Transfer rowKey={record => record.uid} />;