• English
  • Structured data

    We also provide components for structured data input:

    • ProFormList: Used for inputting structured multidimensional array data.
    • ProFormFieldSet: Used for inputting structured one-dimensional array data.
    • ProFormDependency: Components for managing data dependencies.

    ProFormList

    ProFormList is basically the same as the Form.List API. It adds its own operation buttons: delete and copy, and it also includes a new row button.

    <ProFormList
      name="users"
      initialValue={[
        {
          useMode: 'chapter',
        },
      ]}
      creatorButtonProps={{
        position: 'top',
        creatorButtonText: 'Building a line',
      }}
      creatorRecord={{
        useMode: 'none',
      }}
    >
      <ProFormSelect
        key="useMode"
        options={[
          {
            value: 'chapter',
            label: 'Valid after stamping',
          },
          {
            value: 'none',
            label: 'Not effective',
          },
        ]}
        width="md"
        name="useMode"
        label="Contract agreement effective method"
      />
    </ProFormList>

    ProFormList API

    ParametersDescriptionTypeDefault Value
    itemRendercustom Item, it can be used to place actions in other locations(doms,listMeta)=> ReactNode-
    itemContainerRendercustom Item container, e.g. wrap each item in a Card(doms,listMeta)=> ReactNode-
    creatorRecordDefault value of a new lineRecord<string, any> | () => Record<string, any>-
    creatorButtonPropsConfiguration of a new line of buttons, set false to hide itfalse | (ButtonProps & &#123; creatorButtonText?: ReactNode, position?: "top"|"bottom" &#125;){creatorButtonText:"Create a new line"}
    labelSame as From.ItemReactNode-
    tooltipTooltip info next to the titleLabelTooltipType-
    nameThe value of list in the form, requiredNamePath-
    alwaysShowItemLabelalways show label in Itemboolean-
    actionRefThe built-in operation of the current List, you can add, delete, modify and check list itemsMutableRefObject<{add,remove,move,get,getList} | undefined>-
    actionGuardFormItem's interceptor, including deletion and addition interception, you can use actionRef to get the value of the current row{beforeAddRow:(defaultValue,index,count)=>boolean|Promise<boolean>, beforeRemoveRow:(index,count)=>boolean|Promise<boolean>&#125;-
    minThe minimum number of entries, if the current data entry is less than this number, it cannot be deletednumber-
    maxThe maximum number of entries, when adding or copying, if the current data entry exceeds this number, it cannot be added or copiednumber-
    copyIconPropsCopy button configuration, false to cancel{ Icon?: React.FC<any>; tooltipText?: string; } | false-
    deleteIconPropsDelete button configuration, false can cancel{ Icon?: React.FC<any>; tooltipText?: string; } | false-
    actionRendercustom action button(field,action,defaultActionDom,count)=>React.ReactNode[]-
    fieldExtraRenderAppend a dom at the end, e.g. a custom create button(fieldAction,meta)=> ReactNode-
    onAfterAddHook after adding data(defaultValue: StoreValue, insertIndex: number, count: number) => void-
    onAfterRemoveHook after deleting data(index: number, count: number) => void-
    arrowSortWhether to enable arrow button sortingboolean-
    upIconPropsSort-up button configuration, false to cancel{ Icon?: React.FC<any>; tooltipText?: string; } | false-
    downIconPropsSort-down button configuration, false to cancel{ Icon?: React.FC<any>; tooltipText?: string; } | false-
    transformConvert value on submit, generally used to transform values into submitted data(value, namePath, allValues) => any-
    isValidateListWhether to validate the list is empty at the same timebooleanfalse
    emptyListMessageEmpty list message shown when isValidateList is truestring-
    readonlyWhether read-only modeboolean-
    requiredWhether required (used with rules to show validation message)boolean-

    actionRef Action item instance

    const actionRef = useRef<
      FormListActionType<{
        name: string;
      }>
    >();
    
    return (
      /**
       * @name gets the list operation instance
       * @description can delete, add, move and other operations
       *
       * @example actionRef?.current.add?.({},1);
       * @example actionRef?.current.remove?.(1);
       * @example actionRef?.current.move?.(1,2);
       * @example actionRef?.current.get?.(1);
       */
      <>
        <Space>
          <Button
            type="primary"
            onClick={() => {
              const list = actionRef.current?.getList();
              actionRef.current?.add({
                name: 'New' + list?.length,
              });
            }}
          >
            add a line
          </Button>
          <Button
            danger
            onClick={() => {
              actionRef.current?.remove(1);
            }}
          >
            delete a line
          </Button>
          <Button
            onClick={() => {
              actionRef.current?.move(1, 0);
            }}
          >
            move to the first line
          </Button>
          <Button
            type="dashed"
            onClick={() => {
              const row = actionRef.current?.get(1);
              console.log(row);
            }}
          >
            Get a row of data
          </Button>
          <Button
            type="dashed"
            onClick={() => {
              const row = actionRef.current?.getList();
              console.log(row);
            }}
          >
            get all data
          </Button>
        </Space>
        <ProFormList actionGuard={actionGuard} actionRef={actionRef}>
          <ProFormText key="useMode" name="name" label="name" />
        </ProFormList>
      </>
    );

    actionGuard interceptor

    actionGuard can intercept list operations, and now there are two events beforeAddRow and beforeRemoveRow.

    const actionRef = useRef<
      FormListActionType<{
        name: string;
      }>
    >();
    const actionGuard = {
      beforeAddRow: async (defaultValue, insertIndex, count) => {
        return new Promise((resolve) => {
          console.log(defaultValue?.name, insertIndex, count);
          setTimeout(() => resolve(true), 1000);
        });
      },
      beforeRemoveRow: async (index, count) => {
        const row = actionRef.current?.get(index as number);
        console.log('--->', index, count, row);
        return new Promise((resolve) => {
          if (index === 0) {
            resolve(false);
            return;
          }
          setTimeout(() => resolve(true), 1000);
        });
      },
    };
    return (
      <ProFormList actionGuard={actionGuard} actionRef={actionRef}>
        <ProFormText key="useMode" name="name" label="name" />
      </ProFormList>
    );

    actionRender custom action button

      /**
       * @name custom action button
       *
       * @example delete button
       * actionRender:(field,action)=><a onClick={()=>action.remove(field.name)}>remove</a>
       * @example can only add up to three new lines
       * actionRender:(f,action,_,count)=><a onClick={()=>
       * count>2?alert("Up to three lines!"):action.add({id:"xx"})}>delete
       * </a>
       */
      actionRender?: (
        field: FormListFieldData,
        /**
         * Operational ability
         * @example action.add(data) add a new line
         * @example action.remove(index) delete a line
         * @example action.move(formIndex,targetIndex) move a row
         */
        action: FormListOperation,
        /**
         * Default operation dom
         * [copy, delete]
         */
        defaultActionDom: ReactNode[],
        /**
         * There are currently several list items
         */
        count: number,
      ) => ReactNode[];
    

    ProFormList RenderProps mode

    ProFormList supports passing in a method to get the information and shortcut operations of the current row, which is very convenient for complex linkage.

    <ProFormList>
      {(
        // Basic information of the current row {name: number; key: number}
        meta,
        // current line number
        index,
        /**
         * action
         * @name some shortcut methods for manipulating rows
         * @example add data to the second line action.add?.({},1);
         * @example delete the second line action.remove?.(1);
         * @example moved from 1 to 2: action.move?.(2,1);
         * @example Get the data of the current row: action.getCurrentRowData() -> {id:"xxx",name:'123',age:18}
         * @example Set current row data: {id:"123",name:'123'} -> action.setCurrentRowData({name:'xxx'}) -> {id:"123",name:'xxx' }
         * @example clear the data of the current row: {id:"123",name:'123'} -> action.setCurrentRowData({name:undefined}) -> {id:"123"}
         */
        action,
        // total number of rows
        count,
      ) => {
        return (
          <div key="row">
            <ProFormText name="id" />
            <ProFormText name="name" />
          </div>
        );
      }}
    </ProFormList>

    The types of these four parameters are defined as follows:

    type RenderActionParams = {
      /**
       * @name The meta information of the current line
       * @example {name: number; key: number}
       */
      meta: FormListFieldData;
      /**
       * @name the line number of the current line
       */
      index: number;
      /**
       * @name some shortcut methods for manipulating rows
       * @example add data to the second line action.add?.({},1);
       * @example delete the second line action.remove?.(1);
       * @example moved from 1 to 2: action.move?.(2,1);
       * @example Get the data of the current row: action.getCurrentRowData() -> {id:"xxx",name:'123',age:18}
       * @example Set current row data: {id:"123",name:'123'} -> action.setCurrentRowData({name:'xxx'}) -> {id:"123",name:'xxx' }
       * @example clear the data of the current row: {id:"123",name:'123'} -> action.setCurrentRowData({name:undefined}) -> {id:"123"}
       */
      action: FormListOperation & {
        /**
         * @name Get the data of the current row
         * @example getCurrentRowData -> {id:"xxx",name:'123',age:18}
         */
        getCurrentRowData: () => any;
        /**
         * @name sets the data of the current row
         * @example {id:"123",name:'123'} -> setCurrentRowData({name:'xxx'}) -> {id:"123",name:'123'}
         * @example {id:"123",name:'123'} -> setCurrentRowData({name:undefined}) -> {id:"123"}
         */
        setCurrentRowData: (data: any) => void;
      };
      /**
       * @name the total number of rows
       */
      count: number;
    };

    ProFormFieldSet

    ProFormFieldSet can combine the values of multiple children inside and store them in ProForm, and can be transformed at commit time via transform. Here is a simple usage to easily combine multiple input fields and format them to the desired data.

    <ProFormFieldSet
      name="list"
      label="List of components"
      // Two methods are supported, type="group" will be wrapped with input.group
      // If not configured, use space by default
      type="group"
      transform={(value: any) => ({ startTime: value[0], endTime: value[1] })}
    >
      <ProFormText width="md" />
      <ProFormText width="md" />
      <ProFormText width="md" />
    </ProFormFieldSet

    ProFormDependency

    ProFormDependency is a simplified version of Form.Item. It comes with noStyle and shouldUpdate built-in by default. You only need to configure the name parameter to specify which data to depend on. ProFormDependency will automatically handle differences and extract the corresponding values from the form.

    The name parameter must be an array. For nested structures, you can configure it like this: name={['name', ['name2', 'text']]}. The values of the configured name will be passed into renderProps. For example, if name={['name', ['name2', 'text']]}, the values passed will be { name: string, name2: { text: string } }.

    <ProFormDependency name={['name']}>
      {({ name }) => {
        return (
          <ProFormSelect
            options={[
              {
                value: 'chapter',
                label: 'Effective after stamping.',
              },
            ]}
            width="md"
            name="useMode"
            label={`Effective as per the agreement in the contract with《${name}》`}
          />
        );
      }}
    </ProFormDependency>

    Code examples

    Custom tooltip for delete and copy

    ProForm.List
    import { CloseCircleOutlined, SmileOutlined } from '@ant-design/icons';
    import {
      ProForm,
      ProFormGroup,
      ProFormList,
      ProFormText,
    } from '@ant-design/pro-components';
    import { Segmented } from 'antd';
    import { useState } from 'react';
    
    const Demo = () => {
      const [readonly, setReadonly] = useState(false);
      return (
        <div
          style={{
            display: 'flex',
            flexDirection: 'column',
            gap: 16,
          }}
        >
          <Segmented
            block
            options={[
              {
                label: '编辑',
                title: '编辑',
                value: 'edit',
              },
              {
                label: '只读',
                title: '只读',
                value: 'readonly',
              },
            ]}
            onChange={(e) => {
              setReadonly(e === 'readonly');
            }}
          />
          <ProForm
            name="list-tooltip-demo"
            readonly={readonly}
            onFinish={async (e) => console.log(e)}
          >
            <ProFormText name="name" label="姓名" />
            <ProFormList
              name="labels"
              label="用户信息"
              initialValue={[
                {
                  value: '333',
                  label: '333',
                },
              ]}
              copyIconProps={{ Icon: SmileOutlined, tooltipText: '复制此项到末尾' }}
              deleteIconProps={{
                Icon: CloseCircleOutlined,
                tooltipText: '不需要这行了',
              }}
            >
              <ProFormGroup key="group">
                <ProFormText name="value" label="值" />
                <ProFormText name="label" label="显示名称" />
              </ProFormGroup>
            </ProFormList>
          </ProForm>
        </div>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    FormList with dependent fields

    ProForm.List
    import {
      ProForm,
      ProFormDependency,
      ProFormList,
      ProFormText,
    } from '@ant-design/pro-components';
    import { Button } from 'antd';
    
    const Demo = () => {
      return (
        <ProForm name="group-base-use-demo">
          <ProFormList
            name={['default', 'users']}
            label="用户信息"
            initialValue={[
              {
                name: '1111',
              },
            ]}
            itemContainerRender={(doms) => {
              return <ProForm.Group>{doms}</ProForm.Group>;
            }}
            alwaysShowItemLabel
          >
            {(f, index, action) => {
    
              return (
                <>
                  <ProFormText
                    initialValue={index}
                    name="rowKey"
                    label={`第 ${index} 配置`}
                  />
                  <ProFormText name="name" key="name" label="姓名" />
                  <ProFormDependency key="remark" name={['name']}>
                    {({ name }) => {
                      if (!name) {
                        return (
                          <span
                            style={{
                              lineHeight: '92px',
                            }}
                          >
                            输入姓名展示
                          </span>
                        );
                      }
                      return <ProFormText name="remark" label="昵称详情" />;
                    }}
                  </ProFormDependency>
                  <div
                    style={{
                      display: 'flex',
                      alignItems: 'flex-end',
                      gap: '8px',
                      height: 60,
                    }}
                  >
                    <Button
                      type="primary"
                      key="SET"
                      onClick={() => {
                        action.setCurrentRowData({
                          name: 'New Name' + index,
                          remark: 'New Remark' + index,
                        });
                      }}
                    >
                      设置此项
                    </Button>
    
                    <Button
                      type="dashed"
                      key="clear"
                      onClick={() => {
                        action.setCurrentRowData({
                          name: undefined,
                          remark: undefined,
                        });
                      }}
                    >
                      清空此项
                    </Button>
                  </div>
                </>
              );
            }}
          </ProFormList>
        </ProForm>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Adjustable position for the create button

    男性
    请选择
    请选择
    ProForm.List-position
    import {
      ProForm,
      ProFormDatePicker,
      ProFormDigit,
      ProFormFieldSet,
      ProFormGroup,
      ProFormList,
      ProFormRadio,
      ProFormSelect,
      ProFormText,
    } from '@ant-design/pro-components';
    import { ConfigProvider } from 'antd';
    import { useState } from 'react';
    
    const Demo = () => {
      const [position, setPosition] = useState<'bottom' | 'top'>('bottom');
      return (
        <ConfigProvider componentSize="small">
          <ProFormRadio.Group
            fieldProps={{
              value: position,
              onChange: (e) => setPosition(e.target.value),
            }}
            options={[
              {
                label: '顶部',
                value: 'top',
              },
              {
                label: '底部',
                value: 'bottom',
              },
            ]}
          />
          <ProForm
            name="group-list-demo"
            onFinish={async () => {
    
            }}
          >
            <ProFormText width="sm" name="id" label="主合同编号" />
            <ProFormText
              name="project"
              width="md"
              label="项目名称"
              initialValue="示例项目"
            />
            <ProFormText
              width="xs"
              name="mangerName"
              label="商务经理"
              initialValue="书琰"
            />
            <ProFormList
              name="users"
              label="用户信息"
              rules={[
                {
                  required: true,
                  validator: async (_, value) => {
    
                    if (value && value.length > 0) {
                      return;
                    }
                    throw new Error('至少要有一项!');
                  },
                },
              ]}
              creatorButtonProps={{
                position,
              }}
              creatorRecord={{
                name: '',
              }}
              initialValue={[
                {
                  name: '书琰',
                  nickName: '琰琰',
                  age: 28,
                  birth: '2024-01-15',
                  sex: 'man',
                  addrList: [{ addr: ['taiyuan', 'changfeng'] }],
                },
              ]}
            >
              <ProFormGroup key="group">
                <ProFormText
                  rules={[
                    {
                      required: true,
                    },
                  ]}
                  name="name"
                  label="姓名"
                />
                <ProFormDigit name="age" label="年龄" width="sm" />
                <ProFormSelect
                  label="性别"
                  name="sex"
                  width="xs"
                  valueEnum={{
                    man: '男性',
                    woman: '女性',
                  }}
                />
                <ProFormDatePicker name="birth" label="出生日期" />
                <ProFormFieldSet name="addr" label="地址">
                  <ProFormSelect
                    valueEnum={{
                      taiyuan: '山西',
                      hangzhou: '杭州',
                    }}
                  />
                  <ProFormSelect
                    valueEnum={{
                      changfeng: '长风街',
                      gongzhuan: '工专路',
                    }}
                  />
                </ProFormFieldSet>
              </ProFormGroup>
            </ProFormList>
          </ProForm>
        </ConfigProvider>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Forms nested within each other

    1111
    ProForm.List-ProFormList
    import {
      ProCard,
      ProForm,
      ProFormGroup,
      ProFormList,
      ProFormText,
    } from '@ant-design/pro-components';
    
    
    const Demo = () => {
      return (
        <ProForm name="nested-list-demo" onFinish={async (e) => console.log(e)}>
          <ProFormText name="name" label="姓名" />
          <ProFormList
            name="users"
            label="用户信息"
            initialValue={[
              {
                name: '1111',
              },
            ]}
            itemRender={({ listDom, action }, { record }) => {
              return (
                <ProCard
                  variant="outlined"
                  extra={action}
                  title={record?.name}
                  style={{
                    marginBlockEnd: 8,
                  }}
                >
                  {listDom}
                </ProCard>
              );
            }}
          >
            <ProFormGroup>
              <ProFormText name="name" label="姓名" />
              <ProFormText name="nickName" label="昵称" />
            </ProFormGroup>
            <ProFormList
              name="labels"
              label="用户信息"
              initialValue={[
                {
                  value: '333',
                  label: '333',
                },
              ]}
              copyIconProps={{
                tooltipText: '复制此项到末尾',
              }}
              deleteIconProps={{
                tooltipText: '不需要这行了',
              }}
            >
              <ProFormGroup key="group">
                <ProFormText name="value" label="值" />
                <ProFormText name="label" label="显示名称" />
              </ProFormGroup>
            </ProFormList>
          </ProFormList>
        </ProForm>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Complex field dependencies

    请选择
    ProForm.List-dependency
    import {
      ProForm,
      ProFormDependency,
      ProFormList,
      ProFormSelect,
      ProFormText,
    } from '@ant-design/pro-components';
    
    const Demo = () => {
      return (
        <ProForm name="group-dependency-demo">
          <ProFormList
            name={['default', 'users']}
            label="用户信息"
            initialValue={[
              {
                name: '我是姓名',
              },
            ]}
            itemContainerRender={(doms) => {
              return <ProForm.Group>{doms}</ProForm.Group>;
            }}
          >
            {(f, index, _action) => {
    
              return (
                <>
                  <ProFormText
                    initialValue={index}
                    name="rowKey"
                    label={`第 ${index} 配置`}
                  />
                  <ProFormText name="name" label="姓名" />
                  <ProFormDependency name={['name']}>
                    {({ name }) => {
                      if (!name) {
                        return (
                          <span
                            style={{
                              lineHeight: '32px',
                            }}
                          >
                            输入姓名展示
                          </span>
                        );
                      }
                      return <ProFormText name="remark" label="昵称详情" />;
                    }}
                  </ProFormDependency>
                  <ProFormSelect
                    name="addr"
                    width="md"
                    label="与 name 联动的选择器"
                    dependencies={['name']}
                    request={async (params) => [
                      { label: params.name, value: 'all' },
                      { label: 'Unresolved', value: 'open' },
                      { label: 'Resolved', value: 'closed' },
                      { label: 'Resolving', value: 'processing' },
                    ]}
                  />
                </>
              );
            }}
          </ProFormList>
        </ProForm>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Behavior guard

    1111
    import type { FormListActionType } from '@ant-design/pro-components';
    import {
      ProCard,
      ProForm,
      ProFormGroup,
      ProFormList,
      ProFormText,
    } from '@ant-design/pro-components';
    import { Button, Space, message } from 'antd';
    import { useRef } from 'react';
    
    const Demo = () => {
      const actionRef = useRef<
        FormListActionType<{
          name: string;
        }>
      >();
      return (
        <>
          <Space
            style={{
              marginBlockEnd: 24,
            }}
          >
            <Button
              type="primary"
              onClick={() => {
                const list = actionRef.current?.getList();
                actionRef.current?.add({
                  name: '新增' + list?.length,
                });
              }}
            >
              增加一行
            </Button>
            <Button
              danger
              onClick={() => {
                actionRef.current?.remove(1);
              }}
            >
              删除一行
            </Button>
            <Button
              onClick={() => {
                actionRef.current?.move(1, 0);
              }}
            >
              移动到第一行
            </Button>
            <Button
              type="dashed"
              onClick={() => {
                const row = actionRef.current?.get(1);
                message.info(JSON.stringify(row ?? null));
              }}
            >
              获取一行数据
            </Button>
            <Button
              type="dashed"
              onClick={() => {
                const row = actionRef.current?.getList();
                message.info(JSON.stringify(row ?? []));
              }}
            >
              获取所有数据
            </Button>
          </Space>
          <ProForm name="pro-form-list-demo" onFinish={async (e) => console.log(e)}>
            <ProFormList
              name="users"
              label="用户信息"
              initialValue={[
                {
                  name: '1111',
                },
              ]}
              creatorRecord={{
                name: '222',
              }}
              actionGuard={{
                beforeAddRow: async (_defaultValue, _insertIndex) => {
                  return new Promise((resolve) => {
    
                    setTimeout(() => resolve(true), 1000);
                  });
                },
                beforeRemoveRow: async (index) => {
                  return new Promise((resolve) => {
                    if (index === 0) {
                      message.error('这行不能删');
                      resolve(false);
                      return;
                    }
                    setTimeout(() => resolve(true), 1000);
                  });
                },
              }}
              itemRender={({ listDom, action }, { record }) => {
                return (
                  <ProCard
                    variant="outlined"
                    extra={action}
                    title={record?.name}
                    style={{
                      marginBlockEnd: 8,
                    }}
                  >
                    {listDom}
                  </ProCard>
                );
              }}
              actionRef={actionRef}
            >
              <ProFormGroup key="group">
                <ProFormText name="name" label="姓名" />
                <ProFormText name="age" label="年龄" />
              </ProFormGroup>
            </ProFormList>
          </ProForm>
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Limitations on adding or deleting items

    import { CloseOutlined, SnippetsOutlined } from '@ant-design/icons';
    import type { FormListActionType } from '@ant-design/pro-components';
    import { ProForm, ProFormList, ProFormText } from '@ant-design/pro-components';
    import { useRef } from 'react';
    
    const Demo = () => {
      const actionRef = useRef<
        FormListActionType<{
          name: string;
        }>
      >();
      return (
        <>
          <ProForm name="group-countlimit-demo">
            <ProFormList
              copyIconProps={{
                Icon: SnippetsOutlined,
              }}
              deleteIconProps={{
                Icon: CloseOutlined,
              }}
              min={1}
              max={4}
              actionRef={actionRef}
              actionGuard={{
                beforeAddRow: async (_defaultValue, _insertIndex, _count) => {
                  return new Promise((resolve) => {
    
                    setTimeout(() => resolve(true), 1000);
                  });
                },
                beforeRemoveRow: async (index, _count) => {
                  const _row = actionRef.current?.get(index as number);
    
                  return new Promise((resolve) => {
                    if (index === 0) {
                      resolve(false);
                      return;
                    }
                    setTimeout(() => resolve(true), 1000);
                  });
                },
              }}
              name="users"
              label="用户信息"
              initialValue={[
                {
                  name: '1111',
                },
              ]}
            >
              <ProFormText key="useMode" name="name" label="姓名" />
            </ProFormList>
          </ProForm>
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Horizontal layout

    规格1
    import {
      ProCard,
      ProForm,
      ProFormList,
      ProFormText,
    } from '@ant-design/pro-components';
    
    const Demo = () => {
      return (
        <ProForm name="horizontal-layout-demo" layout="horizontal">
          <ProFormList
            name="attributes"
            label="规格"
            creatorButtonProps={{
              creatorButtonText: '添加规格项',
            }}
            min={1}
            copyIconProps={false}
            itemRender={({ listDom, action }, { index }) => (
              <ProCard
                variant="outlined"
                style={{ marginBlockEnd: 8 }}
                title={`规格${index + 1}`}
                extra={action}
                styles={{ body: { paddingBlockEnd: 0 } }}
              >
                {listDom}
              </ProCard>
            )}
            creatorRecord={{ name: '', items: [{ name: '' }] }}
            initialValue={[
              { name: '颜色', items: [{ name: '红' }, { name: '黄' }] },
            ]}
          >
            <ProFormText
              style={{ padding: 0 }}
              width="md"
              name="name"
              label="规格名"
            />
            <ProForm.Item isListField style={{ marginBlockEnd: 0 }} label="规格值">
              <ProFormList
                name="items"
                creatorButtonProps={{
                  creatorButtonText: '新建',
                  icon: false,
                  type: 'link',
                  style: { width: 'unset' },
                }}
                min={1}
                copyIconProps={false}
                deleteIconProps={{ tooltipText: '删除' }}
                itemRender={({ listDom, action }) => (
                  <div
                    style={{
                      display: 'inline-flex',
                      marginInlineEnd: 25,
                    }}
                  >
                    {listDom}
                    {action}
                  </div>
                )}
              >
                <ProFormText allowClear={false} width="xs" name={['name']} />
              </ProFormList>
            </ProForm.Item>
          </ProFormList>
        </ProForm>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Arrow sort reordering

    Reorder list items with arrows
    import {
      ProForm,
      ProFormGroup,
      ProFormList,
      ProFormText,
    } from '@ant-design/pro-components';
    
    
    const Demo = () => {
      return (
        <div
          style={{
            display: 'flex',
            flexDirection: 'column',
            gap: 16,
          }}
        >
          <ProForm
            name="list-arrowsort-demo"
            onFinish={async (e) => console.log(e)}
          >
            <ProFormText name="name" label="姓名" />
    
            <ProFormList
              name="labels"
              label="用户信息"
              initialValue={[
                {
                  value: '111',
                  label: '111',
                },
                {
                  value: '222',
                  label: '222',
                },
                {
                  value: '333',
                  label: '333',
                },
              ]}
              arrowSort={true}
              upIconProps={{ tooltipText: '' }}
            >
              <ProFormGroup key="group">
                <ProFormText name="value" label="值" />
                <ProFormText name="label" label="显示名称" />
              </ProFormGroup>
            </ProFormList>
          </ProForm>
        </div>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );