• English
  • ProList - Advanced List

    ProList is built on top of ProTable and can be considered a special variant, presenting data in list form. Its API design is similar to Table, making it easy to switch between Table and List.

    When to use

    When you need a standard list presentation, or need to flexibly switch between list and table forms, ProList is the right choice.

    Code demo

    Issue regression scenarios

    等待请求完成
    暂无数据
    暂无数据
    • 第 0-0 条/总共 0 条
    • 1
    Display controls and live pagination state
    import type { ActionType, ProColumns } from '@ant-design/pro-components';
    import { ProCard, ProList } from '@ant-design/pro-components';
    import { Alert, Button, Space, Typography } from 'antd';
    import { useRef, useState } from 'react';
    
    type Item = { id: number; title: string; description: string };
    
    const columns: ProColumns<Item>[] = [
      { dataIndex: 'title', title: '标题', listSlot: 'title' },
      { dataIndex: 'description', title: '说明', listSlot: 'description' },
      {
        title: '操作',
        listSlot: 'actions',
        render: () => [<a key="edit">编辑</a>],
      },
    ];
    
    export default () => {
      const actionRef = useRef<ActionType>();
      const [pageInfo, setPageInfo] = useState('等待请求完成');
    
      return (
        <ProCard direction="column" ghost gutter={[0, 16]}>
          <Alert
            type="info"
            showIcon
            message="ProList 展示与实时分页状态"
            description="覆盖操作区 hover、grid itemRender gutter 及 actionRef.pageInfo。"
          />
          <ProList<Item>
            actionRef={actionRef}
            rowKey="id"
            columns={columns}
            showActions="hover"
            grid={{ column: 2, gutter: [16, 24] }}
            pagination={{ pageSize: 2 }}
            request={async () => ({
              success: true,
              total: 42,
              data: [
                { id: 1, title: '项目 A', description: '悬停显示操作区' },
                { id: 2, title: '项目 B', description: '卡片间距保持一致' },
              ],
            })}
            itemRender={(item, index, defaultDom) => (
              <ProCard title={`自定义 itemRender ${index + 1}`}>
                {defaultDom}
              </ProCard>
            )}
            toolBarRender={() => [
              <Space key="page-info">
                <Button
                  onClick={() =>
                    setPageInfo(JSON.stringify(actionRef.current?.pageInfo))
                  }
                >
                  读取 pageInfo
                </Button>
                <Typography.Text code>{pageInfo}</Typography.Text>
              </Space>,
            ]}
          />
        </ProCard>
      );
    };
    

    Basic usage

    项目列表
    书琰

    Ant Design Pro
    进行中

    开箱即用的中台前端/设计解决方案
    React
    TypeScript
    Ant Design
    逄一

    ProComponents
    进行中

    专业级别的中后台组件库
    React
    Components
    期贤

    UmiJS
    进行中

    插件化的企业级前端应用框架
    Framework
    React
    玄霜

    Ant Design Mobile
    待启动

    移动端设计规范和组件库
    Mobile
    React
    怀渊

    Ant Design Charts
    已归档

    简单好用的 React 图表库
    Charts
    Visualization
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProList } from '@ant-design/pro-components';
    import { Avatar, Space, Tag } from 'antd';
    
    type ProjectItem = {
      id: string;
      name: string;
      description: string;
      status: 'active' | 'archived' | 'pending';
      owner: {
        name: string;
        avatar: string;
      };
      tags: string[];
      updatedAt: string;
    };
    
    const statusMap = {
      active: { text: '进行中', color: 'success' },
      archived: { text: '已归档', color: 'default' },
      pending: { text: '待启动', color: 'warning' },
    };
    
    const dataSource: ProjectItem[] = [
      {
        id: '1',
        name: 'Ant Design Pro',
        description: '开箱即用的中台前端/设计解决方案',
        status: 'active',
        owner: {
          name: '书琰',
          avatar:
            'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
        },
        tags: ['React', 'TypeScript', 'Ant Design'],
        updatedAt: '2024-02-09',
      },
      {
        id: '2',
        name: 'ProComponents',
        description: '专业级别的中后台组件库',
        status: 'active',
        owner: {
          name: '逄一',
          avatar:
            'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        },
        tags: ['React', 'Components'],
        updatedAt: '2024-02-08',
      },
      {
        id: '3',
        name: 'UmiJS',
        description: '插件化的企业级前端应用框架',
        status: 'active',
        owner: {
          name: '期贤',
          avatar:
            'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
        },
        tags: ['Framework', 'React'],
        updatedAt: '2024-02-07',
      },
      {
        id: '4',
        name: 'Ant Design Mobile',
        description: '移动端设计规范和组件库',
        status: 'pending',
        owner: {
          name: '玄霜',
          avatar:
            'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        },
        tags: ['Mobile', 'React'],
        updatedAt: '2024-02-06',
      },
      {
        id: '5',
        name: 'Ant Design Charts',
        description: '简单好用的 React 图表库',
        status: 'archived',
        owner: {
          name: '怀渊',
          avatar:
            'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
        },
        tags: ['Charts', 'Visualization'],
        updatedAt: '2024-02-05',
      },
    ];
    
    const columns: ProColumns<ProjectItem>[] = [
      {
        title: '项目名称',
        dataIndex: 'name',
        listSlot: 'title',
      },
      {
        title: '描述',
        dataIndex: 'description',
        listSlot: 'description',
      },
      {
        title: '负责人',
        dataIndex: ['owner', 'avatar'],
        listSlot: 'avatar',
        render: (_, record) => (
          <Avatar src={record.owner.avatar} alt={record.owner.name} />
        ),
      },
      {
        title: '状态',
        dataIndex: 'status',
        listSlot: 'subTitle',
        render: (_, record) => (
          <Tag color={statusMap[record.status].color}>
            {statusMap[record.status].text}
          </Tag>
        ),
      },
      {
        title: '标签',
        dataIndex: 'tags',
        listSlot: 'content',
        render: (_, record) => (
          <Space size={4} wrap>
            {record.tags.map((tag) => (
              <Tag key={tag}>{tag}</Tag>
            ))}
          </Space>
        ),
      },
      {
        title: '操作',
        listSlot: 'actions',
        render: () => [<a key="view">查看</a>, <a key="edit">编辑</a>],
      },
    ];
    
    export default () => (
      <ProList<ProjectItem>
        columns={columns}
        dataSource={dataSource}
        rowKey="id"
        headerTitle="项目列表"
        tooltip="这是一个基础的列表示例,展示了 ProList 的基本用法"
      />
    );
    

    Use columns with the listSlot property to share the same column configuration with ProTable. listSlot specifies which slot of the list item the column maps to (e.g. title, avatar, description).

    columns API(与 ProTable 兼容)

    智慧零售平台
    技术专栏
    设计语言

    Ant Design
    Ant Design
    可视化

    云原生微服务框架
    云原生

    数据可视化引擎
    可视化

    /**
     * 使用 columns + listSlot 的新 API,与 ProTable 兼容
     */
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProList } from '@ant-design/pro-components';
    import { Button, Space, Tag } from 'antd';
    import type { Key } from 'react';
    import { useState } from 'react';
    
    type DataItem = {
      id: string;
      name: string;
      image: string;
      desc: string;
      labels: string[];
    };
    
    const dataSource: DataItem[] = [
      {
        id: '1',
        name: '智慧零售平台',
        image:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        desc: 'Ant Design, a design language for background applications, is refined by Ant UED Team',
        labels: ['技术专栏', '设计语言'],
      },
      {
        id: '2',
        name: 'Ant Design',
        image:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        desc: '企业级数据看板与可视化分析工具,开箱即用的图表方案',
        labels: ['Ant Design', '可视化'],
      },
      {
        id: '3',
        name: '云原生微服务框架',
        image:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        desc: '基于 K8s 的微服务开发与治理框架,支持服务注册与发现',
        labels: ['云原生'],
      },
      {
        id: '4',
        name: '数据可视化引擎',
        image:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        desc: '面向企业级中后台的数据可视化解决方案',
        labels: ['可视化'],
      },
    ];
    
    /**
     * 同一份 columns 可同时用于 ProTable 和 ProList
     * ProTable 忽略 listSlot,ProList 使用 listSlot 映射到列表项的各个部分
     */
    const columns: ProColumns<DataItem>[] = [
      {
        title: '名称',
        dataIndex: 'name',
        listSlot: 'title',
      },
      {
        dataIndex: 'image',
        listSlot: 'avatar',
        search: false,
      },
      {
        title: '标签',
        dataIndex: 'labels',
        listSlot: 'subTitle',
        search: false,
        render: (_, row) => (
          <Space size={8}>
            {row.labels?.map((label) => (
              <Tag color="blue" key={label}>
                {label}
              </Tag>
            ))}
          </Space>
        ),
      },
      {
        title: '描述',
        dataIndex: 'desc',
        listSlot: 'description',
        search: false,
      },
      {
        title: '操作',
        listSlot: 'actions',
        search: false,
        render: () => [<a key="edit">编辑</a>, <a key="delete">删除</a>],
      },
    ];
    
    const Demo = () => {
      const [expandedRowKeys, setExpandedRowKeys] = useState<readonly Key[]>([]);
    
      return (
        <ProList<DataItem>
          rowKey="id"
          headerTitle="columns API(与 ProTable 兼容)"
          toolBarRender={() => [
            <Button key="add" type="primary">
              新建
            </Button>,
          ]}
          columns={columns}
          expandable={{
            expandedRowKeys,
            onExpandedRowsChange: setExpandedRowKeys,
          }}
          dataSource={dataSource}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Card list (columns + listSlot)

    卡片列表(columns API)
    ProTable
    稳定版
    高级表格组件,支持搜索、筛选、排序等功能
    表格组件 • 125.0K 下载 • ⭐ 4.8
    ProForm
    稳定版
    高级表单组件,简化表单开发流程
    表单组件 • 98.0K 下载 • ⭐ 4.9
    ProLayout
    稳定版
    开箱即用的中后台布局方案
    布局组件 • 156.0K 下载 • ⭐ 4.7
    ProCard
    稳定版
    可分割的卡片组件,支持多种布局
    卡片组件 • 67.0K 下载 • ⭐ 4.6
    ProDescriptions
    稳定版
    高级描述列表组件,支持编辑和请求
    描述列表 • 45.0K 下载 • ⭐ 4.5
    ProList
    稳定版
    高级列表组件,支持多种展示模式
    列表组件 • 52.0K 下载 • ⭐ 4.7
    ProSkeleton
    测试版
    高级骨架屏组件,更好的加载体验
    骨架屏 • 34.0K 下载 • ⭐ 4.4
    ProField
    稳定版
    统一的字段渲染组件
    字段组件 • 28.0K 下载 • ⭐ 4.3
    • 第 1-8 条/总共 8 条
    • 1
    /**
     * 卡片模式使用 columns + listSlot,推荐使用新的 columns API
     * actions 在卡片模式下默认渲染到 extra 位置
     */
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProList } from '@ant-design/pro-components';
    import { Alert, Tag } from 'antd';
    
    type DataItem = {
      id: string;
      title: string;
      category: string;
      description: string;
      avatar: string;
      downloads: number;
      rating: number;
      status: 'stable' | 'beta' | 'deprecated';
    };
    
    const statusConfig = {
      stable: { text: '稳定版', color: 'success' },
      beta: { text: '测试版', color: 'processing' },
      deprecated: { text: '已废弃', color: 'default' },
    };
    
    const data: DataItem[] = [
      {
        id: '1',
        title: 'ProTable',
        category: '表格组件',
        description: '高级表格组件,支持搜索、筛选、排序等功能',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/upvrAjAPQX/Logo_Tech%252520UI.svg',
        downloads: 125000,
        rating: 4.8,
        status: 'stable',
      },
      {
        id: '2',
        title: 'ProForm',
        category: '表单组件',
        description: '高级表单组件,简化表单开发流程',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/youdaoyun.png',
        downloads: 98000,
        rating: 4.9,
        status: 'stable',
      },
      {
        id: '3',
        title: 'ProLayout',
        category: '布局组件',
        description: '开箱即用的中后台布局方案',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg',
        downloads: 156000,
        rating: 4.7,
        status: 'stable',
      },
      {
        id: '4',
        title: 'ProCard',
        category: '卡片组件',
        description: '可分割的卡片组件,支持多种布局',
        avatar: 'https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg',
        downloads: 67000,
        rating: 4.6,
        status: 'stable',
      },
      {
        id: '5',
        title: 'ProDescriptions',
        category: '描述列表',
        description: '高级描述列表组件,支持编辑和请求',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/upvrAjAPQX/Logo_Tech%252520UI.svg',
        downloads: 45000,
        rating: 4.5,
        status: 'stable',
      },
      {
        id: '6',
        title: 'ProList',
        category: '列表组件',
        description: '高级列表组件,支持多种展示模式',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/youdaoyun.png',
        downloads: 52000,
        rating: 4.7,
        status: 'stable',
      },
      {
        id: '7',
        title: 'ProSkeleton',
        category: '骨架屏',
        description: '高级骨架屏组件,更好的加载体验',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg',
        downloads: 34000,
        rating: 4.4,
        status: 'beta',
      },
      {
        id: '8',
        title: 'ProField',
        category: '字段组件',
        description: '统一的字段渲染组件',
        avatar: 'https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg',
        downloads: 28000,
        rating: 4.3,
        status: 'stable',
      },
    ];
    
    export default () => {
      const columns: ProColumns<DataItem>[] = [
        {
          title: '组件名称',
          dataIndex: 'title',
          listSlot: 'title',
        },
        {
          title: '状态',
          dataIndex: 'status',
          listSlot: 'subTitle',
          render: (_, record) => (
            <Tag color={statusConfig[record.status].color}>
              {statusConfig[record.status].text}
            </Tag>
          ),
        },
        {
          title: '图标',
          dataIndex: 'avatar',
          listSlot: 'avatar',
        },
        {
          title: '内容',
          listSlot: 'content',
          render: (_, record) => (
            <div style={{ flex: 1 }}>
              <div style={{ marginBottom: 8 }}>{record.description}</div>
              <div style={{ color: '#999', fontSize: 12 }}>
                {record.category} • {(record.downloads / 1000).toFixed(1)}K 下载 •
                ⭐ {record.rating}
              </div>
            </div>
          ),
        },
        {
          title: '操作',
          listSlot: 'actions',
          render: () => [<a key="install">安装</a>, <a key="docs">文档</a>],
        },
      ];
    
      return (
        <div
          style={{
            backgroundColor: '#eee',
            margin: -24,
            padding: 24,
          }}
        >
          <Alert
            title="推荐使用 columns + listSlot API"
            description="新的 columns API 与 ProTable 保持一致,通过 listSlot 指定数据在列表项中的位置。相比 metas API 更加灵活和易于维护。"
            type="info"
            showIcon
            style={{ marginBottom: 16 }}
          />
    
          <ProList<DataItem>
            pagination={{ defaultPageSize: 8, showSizeChanger: false }}
            rowSelection={{}}
            grid={{ gutter: 16, column: 2 }}
            columns={columns}
            headerTitle="卡片列表(columns API)"
            dataSource={data}
          />
        </div>
      );
    };
    

    Grid config

    配置面板
    列数 (column): 2
    123456
    间距 (gutter): 8px
    0816243248
    显示边框:
    幽灵模式:
    边框:
    Grid 布局示例
    Analytics Pro
    运行中
    企业级数据分析平台,支持多维度数据分析和可视化展示
    数据分析 • 1,280 用户
    Cloud Storage
    运行中
    安全可靠的企业云存储服务,支持文件同步和共享
    云存储 • 3,450 用户
    Task Manager
    运行中
    高效的任务和项目管理工具,支持团队协作和进度跟踪
    项目管理 • 2,150 用户
    Email Suite
    测试中
    专业的企业邮件服务,支持大附件和邮件加密
    企业邮箱 • 890 用户
    Video Conference
    运行中
    高清视频会议系统,支持屏幕共享和实时字幕
    视频会议 • 5,200 用户
    HR System
    运行中
    一体化人力资源管理系统,涵盖招聘、考勤、薪酬等
    人力资源 • 1,560 用户
    CRM Platform
    运行中
    智能客户关系管理平台,助力销售业绩提升
    客户关系 • 2,890 用户
    Finance Suite
    运行中
    专业的财务管理系统,支持多币种和自动对账
    财务管理 • 1,120 用户
    Workflow Engine
    测试中
    灵活的工作流引擎,支持可视化流程设计
    流程引擎 • 670 用户
    Knowledge Base
    运行中
    企业知识管理系统,支持全文检索和智能推荐
    知识库 • 1,940 用户
    Security Center
    运行中
    企业安全管理中心,实时监控和威胁检测
    安全中心 • 780 用户
    API Gateway
    测试中
    统一的 API 网关服务,支持流量控制和监控
    接口网关 • 450 用户
    • 第 1-12 条/总共 12 条
    • 1
    import { ProList } from '@ant-design/pro-components';
    import { Alert, Card, Col, Row, Segmented, Slider, Switch, Tag } from 'antd';
    import { useState } from 'react';
    
    const apps = [
      {
        id: '1',
        name: 'Analytics Pro',
        category: '数据分析',
        description: '企业级数据分析平台,支持多维度数据分析和可视化展示',
        icon: 'https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg',
        status: 'active',
        users: 1280,
      },
      {
        id: '2',
        name: 'Cloud Storage',
        category: '云存储',
        description: '安全可靠的企业云存储服务,支持文件同步和共享',
        icon: 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/youdaoyun.png',
        status: 'active',
        users: 3450,
      },
      {
        id: '3',
        name: 'Task Manager',
        category: '项目管理',
        description: '高效的任务和项目管理工具,支持团队协作和进度跟踪',
        icon: 'https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg',
        status: 'active',
        users: 2150,
      },
      {
        id: '4',
        name: 'Email Suite',
        category: '企业邮箱',
        description: '专业的企业邮件服务,支持大附件和邮件加密',
        icon: 'https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg',
        status: 'beta',
        users: 890,
      },
      {
        id: '5',
        name: 'Video Conference',
        category: '视频会议',
        description: '高清视频会议系统,支持屏幕共享和实时字幕',
        icon: 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/youdaoyun.png',
        status: 'active',
        users: 5200,
      },
      {
        id: '6',
        name: 'HR System',
        category: '人力资源',
        description: '一体化人力资源管理系统,涵盖招聘、考勤、薪酬等',
        icon: 'https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg',
        status: 'active',
        users: 1560,
      },
      {
        id: '7',
        name: 'CRM Platform',
        category: '客户关系',
        description: '智能客户关系管理平台,助力销售业绩提升',
        icon: 'https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg',
        status: 'active',
        users: 2890,
      },
      {
        id: '8',
        name: 'Finance Suite',
        category: '财务管理',
        description: '专业的财务管理系统,支持多币种和自动对账',
        icon: 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/youdaoyun.png',
        status: 'active',
        users: 1120,
      },
      {
        id: '9',
        name: 'Workflow Engine',
        category: '流程引擎',
        description: '灵活的工作流引擎,支持可视化流程设计',
        icon: 'https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg',
        status: 'beta',
        users: 670,
      },
      {
        id: '10',
        name: 'Knowledge Base',
        category: '知识库',
        description: '企业知识管理系统,支持全文检索和智能推荐',
        icon: 'https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg',
        status: 'active',
        users: 1940,
      },
      {
        id: '11',
        name: 'Security Center',
        category: '安全中心',
        description: '企业安全管理中心,实时监控和威胁检测',
        icon: 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/youdaoyun.png',
        status: 'active',
        users: 780,
      },
      {
        id: '12',
        name: 'API Gateway',
        category: '接口网关',
        description: '统一的 API 网关服务,支持流量控制和监控',
        icon: 'https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg',
        status: 'beta',
        users: 450,
      },
    ];
    
    const statusMap: Record<string, { text: string; color: string }> = {
      active: { text: '运行中', color: 'success' },
      beta: { text: '测试中', color: 'processing' },
    };
    
    const data = apps.map((app) => ({
      id: app.id,
      title: app.name,
      subTitle: (
        <Tag color={statusMap[app.status].color}>{statusMap[app.status].text}</Tag>
      ),
      actions: [<a key="view">打开</a>, <a key="settings">设置</a>],
      avatar: app.icon,
      content: (
        <div>
          <div>{app.description}</div>
          <div style={{ color: '#999', fontSize: 12, marginTop: 8 }}>
            {app.category} • {app.users.toLocaleString()} 用户
          </div>
        </div>
      ),
    }));
    
    export default () => {
      const [column, setColumn] = useState<number>(2);
      const [gutter, setGutter] = useState<number>(8);
      const [bordered, setBordered] = useState<boolean>(true);
      const [ghost, setGhost] = useState<boolean>(false);
    
      return (
        <div style={{ padding: 24, backgroundColor: '#f5f5f5' }}>
          <Alert
            title="Grid 布局配置"
            description="ProList 使用 CSS Grid 实现网格布局,支持自定义列数和间距。通过 grid 属性配置,可以实现响应式的卡片网格布局。"
            type="info"
            showIcon
            style={{ marginBottom: 24 }}
          />
    
          <Card title="配置面板" style={{ marginBottom: 24 }}>
            <Row gutter={[24, 24]}>
              <Col xs={24} md={12}>
                <div>
                  <div style={{ marginBottom: 8, fontWeight: 500 }}>
                    列数 (column): {column}
                  </div>
                  <Slider
                    min={1}
                    max={6}
                    value={column}
                    onChange={setColumn}
                    marks={{
                      1: '1',
                      2: '2',
                      3: '3',
                      4: '4',
                      5: '5',
                      6: '6',
                    }}
                  />
                </div>
              </Col>
    
              <Col xs={24} md={12}>
                <div>
                  <div style={{ marginBottom: 8, fontWeight: 500 }}>
                    间距 (gutter): {gutter}px
                  </div>
                  <Slider
                    min={0}
                    max={48}
                    step={4}
                    value={gutter}
                    onChange={setGutter}
                    marks={{
                      0: '0',
                      8: '8',
                      16: '16',
                      24: '24',
                      32: '32',
                      48: '48',
                    }}
                  />
                </div>
              </Col>
    
              <Col xs={24} md={8}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ fontWeight: 500 }}>显示边框:</span>
                  <Switch checked={bordered} onChange={setBordered} />
                </div>
              </Col>
    
              <Col xs={24} md={8}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ fontWeight: 500 }}>幽灵模式:</span>
                  <Switch checked={ghost} onChange={setGhost} />
                </div>
              </Col>
    
              <Col xs={24} md={8}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ fontWeight: 500 }}>边框:</span>
                  <Segmented
                    value={bordered ? 'bordered' : 'borderless'}
                    onChange={(v) => setBordered(v === 'bordered')}
                    options={[
                      { label: '有边框', value: 'bordered' },
                      { label: '无边框', value: 'borderless' },
                    ]}
                  />
                </div>
              </Col>
            </Row>
    
            <Alert
              title="代码示例"
              description={
                <pre style={{ margin: 0, fontSize: 12 }}>
                  {`<ProList
      grid={{ gutter: ${gutter}, column: ${column} }}
      itemCardProps={{ bordered: ${bordered}, ghost: ${ghost} }}
      ...
    />`}
                </pre>
              }
              type="success"
              style={{ marginTop: 24 }}
            />
          </Card>
    
          <ProList<any>
            grid={{ gutter, column }}
            itemCardProps={{
              bordered,
              ghost,
            }}
            ghost={ghost}
            pagination={{
              defaultPageSize: 12,
              showSizeChanger: true,
              pageSizeOptions: ['6', '12', '18', '24'],
            }}
            columns={[
              { dataIndex: 'title', listSlot: 'title' },
              { dataIndex: 'subTitle', listSlot: 'subTitle' },
              { dataIndex: 'avatar', listSlot: 'avatar' },
              { dataIndex: 'content', listSlot: 'content' },
              { dataIndex: 'actions', listSlot: 'actions' },
            ]}
            headerTitle="Grid 布局示例"
            tooltip="使用 CSS Grid 实现的响应式卡片布局"
            dataSource={data}
          />
        </div>
      );
    };
    

    Table/List view switching

    Use the same columns for both ProTable and ProList. Switch between table and list views seamlessly by toggling the component.

    列表视图

    智慧零售平台
    技术专栏
    设计语言

    2024-01-15

    Ant Design
    Ant Design

    2024-02-20

    云原生微服务框架
    云原生
    可视化

    2024-03-10
    /**
     * 同一份 columns 同时用于 ProTable 和 ProList,一键切换视图
     */
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProList, ProTable } from '@ant-design/pro-components';
    import { Radio, Space, Tag } from 'antd';
    import { useState } from 'react';
    
    type DataItem = {
      id: string;
      name: string;
      avatar: string;
      status: 'open' | 'closed' | 'processing';
      labels: string[];
      updatedAt: string;
    };
    
    const dataSource: DataItem[] = [
      {
        id: '1',
        name: '智慧零售平台',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        status: 'open',
        labels: ['技术专栏', '设计语言'],
        updatedAt: '2024-01-15',
      },
      {
        id: '2',
        name: 'Ant Design',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        status: 'processing',
        labels: ['Ant Design'],
        updatedAt: '2024-02-20',
      },
      {
        id: '3',
        name: '云原生微服务框架',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        status: 'closed',
        labels: ['云原生', '可视化'],
        updatedAt: '2024-03-10',
      },
    ];
    
    /**
     * 这份 columns 同时用于 ProTable 和 ProList
     * - ProTable 渲染为表格列
     * - ProList 通过 listSlot 映射到列表项各部分
     */
    const columns: ProColumns<DataItem>[] = [
      {
        title: '名称',
        dataIndex: 'name',
        listSlot: 'title',
      },
      {
        title: '头像',
        dataIndex: 'avatar',
        listSlot: 'avatar',
        search: false,
        hideInTable: true,
      },
      {
        title: '标签',
        dataIndex: 'labels',
        listSlot: 'subTitle',
        search: false,
        render: (_, row) => (
          <Space size={4}>
            {row.labels?.map((label) => (
              <Tag color="blue" key={label}>
                {label}
              </Tag>
            ))}
          </Space>
        ),
      },
      {
        title: '状态',
        dataIndex: 'status',
        valueType: 'select',
        valueEnum: {
          open: { text: '未解决', status: 'Error' },
          closed: { text: '已解决', status: 'Success' },
          processing: { text: '处理中', status: 'Processing' },
        },
      },
      {
        title: '更新时间',
        dataIndex: 'updatedAt',
        valueType: 'date',
        search: false,
        listSlot: 'description',
      },
      {
        title: '操作',
        listSlot: 'actions',
        search: false,
        render: () => [<a key="edit">编辑</a>, <a key="delete">删除</a>],
      },
    ];
    
    export default () => {
      const [viewMode, setViewMode] = useState<'list' | 'table'>('list');
    
      return (
        <div style={{ padding: 24 }}>
          <Radio.Group
            value={viewMode}
            onChange={(e) => setViewMode(e.target.value)}
            style={{ marginBottom: 16 }}
            optionType="button"
            buttonStyle="solid"
            options={[
              { label: '列表视图', value: 'list' },
              { label: '表格视图', value: 'table' },
            ]}
          />
          {viewMode === 'list' ? (
            <ProList<DataItem>
              rowKey="id"
              headerTitle="列表视图"
              columns={columns}
              dataSource={dataSource}
            />
          ) : (
            <ProTable<DataItem>
              rowKey="id"
              headerTitle="表格视图"
              columns={columns}
              dataSource={dataSource}
              search={false}
              pagination={false}
            />
          )}
        </div>
      );
    };
    

    Search list (columns + request)

    搜索列表(columns API)
    暂无数据
    暂无数据
    • 第 0-0 条/总共 0 条
    • 1
    /**
     * columns API 配合 request 和搜索表单
     */
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProList } from '@ant-design/pro-components';
    import { Button, Space, Tag } from 'antd';
    import request from 'umi-request';
    
    type GithubIssueItem = {
      url: string;
      id: number;
      number: number;
      title: string;
      labels: {
        name: string;
        color: string;
      }[];
      state: string;
      comments: number;
      created_at: string;
      updated_at: string;
      closed_at?: string;
    };
    
    const columns: ProColumns<GithubIssueItem>[] = [
      {
        title: '用户',
        dataIndex: 'user',
        listSlot: 'title',
      },
      {
        dataIndex: 'avatar',
        listSlot: 'avatar',
        search: false,
      },
      {
        dataIndex: 'title',
        listSlot: 'description',
        search: false,
      },
      {
        dataIndex: 'labels',
        listSlot: 'subTitle',
        search: false,
        render: (_, row) => (
          <Space size={8}>
            {row.labels?.map((label: { name: string }) => (
              <Tag color="blue" key={label.name}>
                {label.name}
              </Tag>
            ))}
          </Space>
        ),
      },
      {
        listSlot: 'actions',
        search: false,
        render: (_, row) => [
          <a href={row.url} target="_blank" rel="noopener noreferrer" key="link">
            链路
          </a>,
          <a href={row.url} target="_blank" rel="noopener noreferrer" key="view">
            查看
          </a>,
        ],
      },
      {
        title: '状态',
        dataIndex: 'state',
        valueType: 'select',
        valueEnum: {
          all: { text: '全部', status: 'Default' },
          open: { text: '未解决', status: 'Error' },
          closed: { text: '已解决', status: 'Success' },
        },
      },
    ];
    
    const Demo = () => (
      <ProList<GithubIssueItem>
        toolBarRender={() => [
          <Button key="add" type="primary">
            新建
          </Button>,
        ]}
        search={{ filterType: 'light' }}
        rowKey="id"
        headerTitle="搜索列表(columns API)"
        request={async (params = {} as Record<string, any>) =>
          request<{ data: GithubIssueItem[] }>(
            'https://proapi.azurewebsites.net/github/issues',
            { params },
          )
        }
        pagination={{ pageSize: 5 }}
        columns={columns}
      />
    );
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Editable list (columns)

    可编辑列表(columns API)

    智慧零售平台
    Ant Design
    可视化

    我是一条测试的描述

    Ant Design
    Ant Design
    可视化

    我是一条测试的描述

    云原生微服务框架
    Ant Design
    可视化

    我是一条测试的描述
    /**
     * columns API 配合可编辑列表
     */
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProList } from '@ant-design/pro-components';
    import { Space, Tag } from 'antd';
    import { useState } from 'react';
    
    const defaultData = [
      {
        id: '1',
        name: '智慧零售平台',
        image:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        desc: '我是一条测试的描述',
      },
      {
        id: '2',
        name: 'Ant Design',
        image:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        desc: '我是一条测试的描述',
      },
      {
        id: '3',
        name: '云原生微服务框架',
        image:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        desc: '我是一条测试的描述',
      },
    ];
    
    type DataItem = (typeof defaultData)[number];
    
    const columns: ProColumns<DataItem>[] = [
      {
        title: '名称',
        dataIndex: 'name',
        listSlot: 'title',
      },
      {
        dataIndex: 'image',
        listSlot: 'avatar',
        editable: false,
      },
      {
        title: '描述',
        dataIndex: 'desc',
        listSlot: 'description',
      },
      {
        listSlot: 'subTitle',
        search: false,
        editable: false,
        render: () => (
          <Space size={8}>
            <Tag color="blue">Ant Design</Tag>
            <Tag color="#5BD8A6">可视化</Tag>
          </Space>
        ),
      },
      {
        listSlot: 'actions',
        search: false,
        render: (_, row, __, action) => [
          <a
            onClick={() => {
              action?.startEditable(row.id);
            }}
            key="edit"
          >
            编辑
          </a>,
        ],
      },
    ];
    
    const Demo = () => {
      const [dataSource, setDataSource] = useState<DataItem[]>(defaultData);
      return (
        <ProList<DataItem>
          rowKey="id"
          headerTitle="可编辑列表(columns API)"
          dataSource={dataSource}
          editable={{
            onSave: async (key, record, originRow) => {
              console.log(key, record, originRow);
              return true;
            },
          }}
          onDataSourceChange={setDataSource}
          columns={columns}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Edit list

    基础列表

    智慧零售平台
    Ant Design
    可视化

    我是一条测试的描述

    Ant Design
    Ant Design
    可视化

    我是一条测试的描述

    云原生微服务框架
    Ant Design
    可视化

    我是一条测试的描述

    数据可视化引擎
    Ant Design
    可视化

    我是一条测试的描述
    import { ProList } from '@ant-design/pro-components';
    import { Space, Tag } from 'antd';
    import { useState } from 'react';
    
    const defaultData = [
      {
        id: '1',
        name: '智慧零售平台',
        image:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        desc: '我是一条测试的描述',
      },
      {
        id: '2',
        name: 'Ant Design',
        image:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        desc: '我是一条测试的描述',
      },
      {
        id: '3',
        name: '云原生微服务框架',
        image:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        desc: '我是一条测试的描述',
      },
      {
        id: '4',
        name: '数据可视化引擎',
        image:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        desc: '我是一条测试的描述',
      },
    ];
    
    type DataItem = (typeof defaultData)[number];
    
    const Demo = () => {
      const [dataSource, setDataSource] = useState<DataItem[]>(defaultData);
      return (
        <ProList<DataItem>
          rowKey="id"
          headerTitle="基础列表"
          dataSource={dataSource}
          editable={{
            onSave: async (_key, _record, _originRow) => {
    
              return true;
            },
          }}
          onDataSourceChange={setDataSource}
          columns={[
            { dataIndex: 'name', listSlot: 'title' },
            { dataIndex: 'image', listSlot: 'avatar', editable: false },
            { dataIndex: 'desc', listSlot: 'description' },
            {
              listSlot: 'subTitle',
              render: () => (
                <Space size={8}>
                  <Tag color="blue">Ant Design</Tag>
                  <Tag color="#5BD8A6">可视化</Tag>
                </Space>
              ),
            },
            {
              listSlot: 'actions',
              render: (text, row, index, action) => [
                <a
                  onClick={() => {
                    action?.startEditable(row.id);
                  }}
                  key="link"
                >
                  编辑
                </a>,
              ],
            },
          ]}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    List with toolbar

    全部实验室99
    我创建的实验室32

    实验名称1

    系统性的沉淀B端知识体系
    模型数
    2903
    指标数
    3720
    实验状态
    成功

    实验名称2

    系统性的沉淀B端知识体系
    模型数
    2904
    指标数
    3721
    实验状态
    成功

    实验名称3

    系统性的沉淀B端知识体系
    模型数
    2905
    指标数
    3722
    实验状态
    成功
    import type { ActionType } from '@ant-design/pro-components';
    import { ProList } from '@ant-design/pro-components';
    import { Badge, Button } from 'antd';
    import React, { useRef, useState } from 'react';
    
    const dataSource = [
      {
        name: '实验名称1',
        desc: '系统性的沉淀B端知识体系',
        content: [
          {
            label: '模型数',
            value: 2903,
          },
          {
            label: '指标数',
            value: 3720,
          },
          {
            label: '实验状态',
            value: '成功',
            status: 'success',
          },
        ],
      },
      {
        name: '实验名称2',
        desc: '系统性的沉淀B端知识体系',
        content: [
          {
            label: '模型数',
            value: 2904,
          },
          {
            label: '指标数',
            value: 3721,
          },
          {
            label: '实验状态',
            value: '成功',
            status: 'success',
          },
        ],
      },
      {
        name: '实验名称3',
        desc: '系统性的沉淀B端知识体系',
        content: [
          {
            label: '模型数',
            value: 2905,
          },
          {
            label: '指标数',
            value: 3722,
          },
          {
            label: '实验状态',
            value: '成功',
            status: 'success',
          },
        ],
      },
    ];
    
    const renderBadge = (count: number, active = false) => {
      return (
        <Badge
          count={count}
          style={{
            marginBlockStart: -2,
            marginInlineStart: 4,
            color: active ? '#1890FF' : '#999',
            backgroundColor: active ? '#E6F7FF' : '#eee',
          }}
        />
      );
    };
    
    const Demo = () => {
      const [activeKey, setActiveKey] = useState<React.Key | undefined>('tab1');
      const action = useRef<ActionType>();
      return (
        <ProList<any>
          rowKey="name"
          actionRef={action}
          dataSource={dataSource}
          editable={{}}
          columns={[
            {
              dataIndex: 'name',
              listSlot: 'title',
              valueType: 'select',
              fieldProps: {
                showSearch: true,
                placement: 'bottomRight',
                options: [{ label: '实验名称1', value: '实验名称1' }],
              },
            },
            { dataIndex: 'desc', listSlot: 'description' },
            {
              dataIndex: 'content',
              listSlot: 'content',
              render: (text) => (
                <div
                  key="label"
                  style={{ display: 'flex', justifyContent: 'space-around' }}
                >
                  {(text as any[]).map((t) => (
                    <div key={t.label}>
                      <div>{t.label}</div>
                      <div>
                        {t.status === 'success' && (
                          <span
                            style={{
                              display: 'inline-block',
                              width: 8,
                              height: 8,
                              borderRadius: '50%',
                              backgroundColor: '#52c41a',
                              marginInlineEnd: 8,
                            }}
                          />
                        )}
                        {t.value}
                      </div>
                    </div>
                  ))}
                </div>
              ),
            },
            {
              listSlot: 'actions',
              render: (text, row) => [
                <a
                  key="edit"
                  onClick={() => action.current?.startEditable(row.name)}
                >
                  编辑
                </a>,
                <a key="copy">复制</a>,
                <a key="delete">删除</a>,
              ],
            },
          ]}
          toolbar={{
            menu: {
              activeKey,
              items: [
                {
                  key: 'tab1',
                  label: (
                    <span>全部实验室{renderBadge(99, activeKey === 'tab1')}</span>
                  ),
                },
                {
                  key: 'tab2',
                  label: (
                    <span>
                      我创建的实验室{renderBadge(32, activeKey === 'tab2')}
                    </span>
                  ),
                },
              ],
              onChange(key) {
                setActiveKey(key);
              },
            },
            search: {
              onSearch: (value: string) => {
                alert(value);
              },
            },
            actions: [
              <Button type="primary" key="primary">
                新建实验
              </Button>,
            ],
          }}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Expandable list

    支持展开的列表

    智慧零售平台
    Ant Design
    可视化

    Ant Design
    Ant Design
    可视化

    云原生微服务框架
    Ant Design
    可视化

    数据可视化引擎
    Ant Design
    可视化

    import { ProList } from '@ant-design/pro-components';
    import { Button, Progress, Space, Tag } from 'antd';
    import type { Key } from 'react';
    import { useState } from 'react';
    
    const dataSource = [
      {
        title: '智慧零售平台',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
      },
      {
        title: 'Ant Design',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
      },
      {
        title: '云原生微服务框架',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
      },
      {
        title: '数据可视化引擎',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
      },
    ];
    
    const Demo = () => {
      const [expandedRowKeys, setExpandedRowKeys] = useState<readonly Key[]>([]);
    
      return (
        <ProList<{ title: string }>
          rowKey="title"
          headerTitle="支持展开的列表"
          toolBarRender={() => {
            return [
              <Button key="3" type="primary">
                新建
              </Button>,
            ];
          }}
          expandable={{ expandedRowKeys, onExpandedRowsChange: setExpandedRowKeys }}
          dataSource={dataSource}
          columns={[
            { dataIndex: 'title', listSlot: 'title' },
            {
              listSlot: 'subTitle',
              render: () => (
                <Space size={8}>
                  <Tag color="blue">Ant Design</Tag>
                  <Tag color="#5BD8A6">可视化</Tag>
                </Space>
              ),
            },
            {
              listSlot: 'description',
              render: () => '面向企业级中后台的设计解决方案',
            },
            { dataIndex: 'avatar', listSlot: 'avatar' },
            {
              listSlot: 'content',
              render: () => (
                <div
                  style={{
                    minWidth: 200,
                    flex: 1,
                    display: 'flex',
                    justifyContent: 'flex-end',
                  }}
                >
                  <div
                    style={{
                      width: '200px',
                    }}
                  >
                    <div>发布中</div>
                    <Progress percent={80} />
                  </div>
                </div>
              ),
            },
            {
              listSlot: 'actions',
              render: () => <a key="invite">邀请</a>,
            },
          ]}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    List with row selection

    支持选中的列表

    智慧零售平台

    面向企业级中后台的设计解决方案
    发布中
    80%
    邀请

    Ant Design

    面向企业级中后台的设计解决方案
    发布中
    80%
    邀请

    云原生微服务框架

    面向企业级中后台的设计解决方案
    发布中
    80%
    邀请

    数据可视化引擎

    面向企业级中后台的设计解决方案
    发布中
    80%
    邀请
    import { ProList } from '@ant-design/pro-components';
    import { Button, Progress } from 'antd';
    import type { Key } from 'react';
    import { useState } from 'react';
    
    const dataSource = [
      {
        title: '智慧零售平台',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
      },
      {
        title: 'Ant Design',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
      },
      {
        title: '云原生微服务框架',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
      },
      {
        title: '数据可视化引擎',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
      },
    ];
    
    const Demo = () => {
      const [selectedRowKeys, setSelectedRowKeys] = useState<Key[]>([]);
      const rowSelection = {
        selectedRowKeys,
        onChange: (keys: Key[]) => setSelectedRowKeys(keys),
      };
    
      return (
        <ProList<{ title: string }>
          toolBarRender={() => {
            return [
              <Button key="3" type="primary">
                新建
              </Button>,
            ];
          }}
          columns={[
            { dataIndex: 'title', listSlot: 'title' },
            {
              listSlot: 'description',
              render: () => '面向企业级中后台的设计解决方案',
            },
            { dataIndex: 'avatar', listSlot: 'avatar' },
            {
              listSlot: 'content',
              render: () => (
                <div
                  style={{
                    width: '200px',
                  }}
                >
                  <div>发布中</div>
                  <Progress percent={80} />
                </div>
              ),
            },
            {
              listSlot: 'actions',
              render: () => [
                <a key="init">邀请</a>,
                <Button key="publish" type="text">
                  发布
                </Button>,
              ],
            },
          ]}
          rowKey="title"
          headerTitle="支持选中的列表"
          rowSelection={rowSelection}
          dataSource={dataSource}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Search list

    基础列表
    暂无数据
    暂无数据
    • 第 0-0 条/总共 0 条
    • 1
    import { ProList } from '@ant-design/pro-components';
    import { Button, Space, Tag } from 'antd';
    import request from 'umi-request';
    
    type GithubIssueItem = {
      url: string;
      id: number;
      number: number;
      title: string;
      labels: {
        name: string;
        color: string;
      }[];
      state: string;
      comments: number;
      created_at: string;
      updated_at: string;
      closed_at?: string;
    };
    
    const Demo = () => (
      <ProList<GithubIssueItem>
        toolBarRender={() => {
          return [
            <Button key="3" type="primary">
              新建
            </Button>,
          ];
        }}
        search={{}}
        rowKey="name"
        headerTitle="基础列表"
        request={async (params = {} as Record<string, any>) =>
          request<{
            data: GithubIssueItem[];
          }>('https://proapi.azurewebsites.net/github/issues', {
            params,
          })
        }
        pagination={{
          pageSize: 5,
        }}
        columns={[
          { dataIndex: 'user', listSlot: 'title', title: '用户' },
          { dataIndex: 'avatar', listSlot: 'avatar', search: false },
          { dataIndex: 'title', listSlot: 'description', search: false },
          {
            dataIndex: 'labels',
            listSlot: 'subTitle',
            search: false,
            render: (_, row) => (
              <Space size={0}>
                {row.labels?.map((label: { name: string }) => (
                  <Tag color="blue" key={label.name}>
                    {label.name}
                  </Tag>
                ))}
              </Space>
            ),
          },
          {
            listSlot: 'actions',
            search: false,
            render: (text, row) => [
              <a
                href={row.url}
                target="_blank"
                rel="noopener noreferrer"
                key="link"
              >
                详情
              </a>,
              <a
                href={row.url}
                target="_blank"
                rel="noopener noreferrer"
                key="view"
              >
                查看
              </a>,
            ],
          },
          {
            title: '状态',
            dataIndex: 'status',
            valueType: 'select',
            valueEnum: {
              all: { text: '全部', status: 'Default' },
              open: { text: '未解决', status: 'Error' },
              closed: { text: '已解决', status: 'Success' },
              processing: { text: '解决中', status: 'Processing' },
            },
          },
        ]}
      />
    );
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    List with filtering and asynchronous requests

    基础列表
    暂无数据
    暂无数据
    • 第 0-0 条/总共 0 条
    • 1
    import { ProList } from '@ant-design/pro-components';
    import { Button, Space, Tag } from 'antd';
    import request from 'umi-request';
    
    type GithubIssueItem = {
      url: string;
      id: number;
      number: number;
      title: string;
      labels: {
        name: string;
        color: string;
      }[];
      state: string;
      comments: number;
      created_at: string;
      updated_at: string;
      closed_at?: string;
    };
    
    const Demo = () => (
      <ProList<GithubIssueItem>
        toolBarRender={() => {
          return [
            <Button key="3" type="primary">
              新建
            </Button>,
          ];
        }}
        search={{
          filterType: 'light',
        }}
        rowKey="name"
        headerTitle="基础列表"
        request={async (params = {} as Record<string, any>) =>
          request<{
            data: GithubIssueItem[];
          }>('https://proapi.azurewebsites.net/github/issues', {
            params,
          })
        }
        pagination={{
          pageSize: 5,
        }}
        columns={[
          { dataIndex: 'user', listSlot: 'title', title: '用户' },
          { dataIndex: 'avatar', listSlot: 'avatar', search: false },
          { dataIndex: 'title', listSlot: 'description', search: false },
          {
            dataIndex: 'labels',
            listSlot: 'subTitle',
            search: false,
            render: (_, row) => (
              <Space size={8}>
                {row.labels?.map((label: { name: string }) => (
                  <Tag color="blue" key={label.name}>
                    {label.name}
                  </Tag>
                ))}
              </Space>
            ),
          },
          {
            listSlot: 'actions',
            search: false,
            render: (text, row) => [
              <a
                href={row.url}
                target="_blank"
                rel="noopener noreferrer"
                key="link"
              >
                详情
              </a>,
              <a
                href={row.url}
                target="_blank"
                rel="noopener noreferrer"
                key="view"
              >
                查看
              </a>,
            ],
          },
          {
            title: '状态',
            dataIndex: 'status',
            valueType: 'select',
            valueEnum: {
              all: { text: '全部', status: 'Default' },
              open: { text: '未解决', status: 'Error' },
              closed: { text: '已解决', status: 'Success' },
              processing: { text: '解决中', status: 'Processing' },
            },
          },
        ]}
      />
    );
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Size and divider

    大小:
    default
    分割线:
    有


    大小和分割线

    智慧零售平台

    Ant Design Pro

    云原生微服务框架

    数据可视化引擎

    import { ProList } from '@ant-design/pro-components';
    import { Button, Progress, Select, Tag } from 'antd';
    import type { Key } from 'react';
    import { useState } from 'react';
    
    type ProjectItem = {
      title: string;
      avatar: string;
      description: string;
      progress: number;
      status: string;
    };
    
    const dataSource: ProjectItem[] = [
      {
        title: '智慧零售平台',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        description: '面向线下门店的数字化经营解决方案',
        progress: 85,
        status: '开发中',
      },
      {
        title: 'Ant Design Pro',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        description: '开箱即用的中台前端解决方案',
        progress: 100,
        status: '已上线',
      },
      {
        title: '云原生微服务框架',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        description: '基于 K8s 的微服务开发与治理框架',
        progress: 92,
        status: '测试中',
      },
      {
        title: '数据可视化引擎',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        description: '企业级数据看板与图表分析工具',
        progress: 60,
        status: '开发中',
      },
    ];
    
    const Demo = () => {
      const [selectedRowKeys, setSelectedRowKeys] = useState<Key[]>([]);
      const [expandedRowKeys, setExpandedRowKeys] = useState<readonly Key[]>([]);
      const [size, setSize] = useState<'small' | 'default' | 'large' | undefined>(
        'default',
      );
      const [split, setSplit] = useState<0 | 1>(1);
      const rowSelection = {
        selectedRowKeys,
        onChange: (keys: Key[]) => setSelectedRowKeys(keys),
      };
    
      return (
        <>
          大小:
          <Select<string>
            value={size}
            onChange={(value) => setSize(value as any)}
            options={['small', 'default', 'large'].map((selectSize) => ({
              value: selectSize,
              label: selectSize,
            }))}
          />{' '}
          分割线:
          <Select<0 | 1>
            value={split}
            onChange={(value) => setSplit(value)}
            options={[
              { value: 1, label: '有' },
              { value: 0, label: '无' },
            ]}
          />{' '}
          <br />
          <br />
          <ProList<ProjectItem>
            size={size}
            split={split === 1}
            toolBarRender={() => {
              return [
                <Button key="new" type="primary">
                  新建
                </Button>,
              ];
            }}
            columns={[
              { dataIndex: 'title', listSlot: 'title' },
              { dataIndex: 'description', listSlot: 'description' },
              { dataIndex: 'avatar', listSlot: 'avatar' },
              {
                listSlot: 'content',
                render: (_, record) => (
                  <div
                    style={{
                      minWidth: 200,
                      flex: 1,
                      display: 'flex',
                      justifyContent: 'flex-end',
                    }}
                  >
                    <div style={{ width: 200 }}>
                      <div>
                        {record.status}{' '}
                        <Tag
                          color={record.progress === 100 ? 'success' : 'processing'}
                        >
                          {record.progress}%
                        </Tag>
                      </div>
                      <Progress percent={record.progress} showInfo={false} />
                    </div>
                  </div>
                ),
              },
              {
                listSlot: 'actions',
                render: () => [<a key="invite">邀请</a>],
              },
            ]}
            expandable={{
              expandedRowKeys,
              defaultExpandAllRows: false,
              onExpandedRowsChange: setExpandedRowKeys,
            }}
            rowKey="title"
            headerTitle="大小和分割线"
            rowSelection={rowSelection}
            dataSource={dataSource}
          />
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Vertical style

    竖排样式

    智慧零售平台

    技术专栏
    设计语言
    云原生
    面向企业级中后台的数据可视化解决方案,以最小的接入成本提供丰富的图表类型与交互能力,助力业务快速搭建数据看板与分析报表。
    1561562
    logo

    Ant Design

    技术专栏
    设计语言
    云原生
    面向企业级中后台的数据可视化解决方案,以最小的接入成本提供丰富的图表类型与交互能力,助力业务快速搭建数据看板与分析报表。
    1561562
    logo

    云原生微服务框架

    技术专栏
    设计语言
    云原生
    面向企业级中后台的数据可视化解决方案,以最小的接入成本提供丰富的图表类型与交互能力,助力业务快速搭建数据看板与分析报表。
    1561562
    logo

    数据可视化引擎

    技术专栏
    设计语言
    云原生
    面向企业级中后台的数据可视化解决方案,以最小的接入成本提供丰富的图表类型与交互能力,助力业务快速搭建数据看板与分析报表。
    1561562
    logo
    import { LikeOutlined, MessageOutlined, StarOutlined } from '@ant-design/icons';
    import { ProList } from '@ant-design/pro-components';
    import { Button, Space, Tag } from 'antd';
    import React from 'react';
    
    const IconText = ({ icon, text }: { icon: any; text: string }) => (
      <span>
        {React.createElement(icon, { style: { marginInlineEnd: 8 } })}
        {text}
      </span>
    );
    
    const dataSource = [
      {
        title: '智慧零售平台',
      },
      {
        title: 'Ant Design',
      },
      {
        title: '云原生微服务框架',
      },
      {
        title: '数据可视化引擎',
      },
    ];
    
    const Demo = () => {
      return (
        <ProList<{ title: string }>
          toolBarRender={() => {
            return [
              <Button key="3" type="primary">
                新建
              </Button>,
            ];
          }}
          itemLayout="vertical"
          rowKey="id"
          headerTitle="竖排样式"
          dataSource={dataSource}
          columns={[
            { dataIndex: 'title', listSlot: 'title' },
            {
              listSlot: 'description',
              render: () => (
                <Space orientation="horizontal">
                  <Tag>技术专栏</Tag>
                  <Tag>设计语言</Tag>
                  <Tag>云原生</Tag>
                </Space>
              ),
            },
            {
              listSlot: 'actions',
              render: () => [
                <IconText icon={StarOutlined} text="156" key="star" />,
                <IconText icon={LikeOutlined} text="156" key="like" />,
                <IconText icon={MessageOutlined} text="2" key="message" />,
              ],
            },
            {
              listSlot: 'aside',
              render: () => (
                <img
                  width={272}
                  alt="logo"
                  src="https://gw.alipayobjects.com/zos/rmsportal/mqaQswcyDLcXyDKnZfES.png"
                />
              ),
            },
            {
              listSlot: 'content',
              render: () => (
                <div>
                  面向企业级中后台的数据可视化解决方案,以最小的接入成本提供丰富的图表类型与交互能力,助力业务快速搭建数据看板与分析报表。
                </div>
              ),
            },
          ]}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Some preset modes

    预设的列状态

    智慧零售平台(top)
    技术专栏

    Ant Design Pro(inline)
    技术专栏

    云原生微服务框架(new)
    技术专栏

    数据可视化引擎
    技术专栏

    import { EllipsisOutlined } from '@ant-design/icons';
    import { ProList } from '@ant-design/pro-components';
    import { Button, Progress, Tag } from 'antd';
    import React, { Key, useState } from 'react';
    
    const types = ['top', 'inline', 'new'];
    const data = [
      '智慧零售平台(top)',
      'Ant Design Pro(inline)',
      '云原生微服务框架(new)',
      '数据可视化引擎',
    ].map((item, index) => ({
      title: item,
      subTitle: <Tag color="#5BD8A6">技术专栏</Tag>,
      actions: [
        <a key="invite">邀请</a>,
        <a key="operate">操作</a>,
        <a key="rest">
          <EllipsisOutlined />
        </a>,
      ],
      description: (
        <div>
          <div>top 会有小角标</div>
          <div>inline 标题字体是 normal</div>
          <div>new 会有一个入场动画</div>
        </div>
      ),
      type: types[index],
      avatar:
        'https://gw.alipayobjects.com/zos/antfincdn/UCSiy1j6jx/xingzhuang.svg',
      content: (
        <div
          style={{
            flex: 1,
            display: 'flex',
            justifyContent: 'flex-end',
          }}
        >
          <div
            style={{
              width: 200,
            }}
          >
            <div>发布中</div>
            <Progress percent={80} />
          </div>
        </div>
      ),
    }));
    
    const Demo = () => {
      const [expandedRowKeys, setExpandedRowKeys] = useState<readonly Key[]>([]);
      const [selectedRowKeys, setSelectedRowKeys] = useState<Key[]>([]);
      const rowSelection = {
        selectedRowKeys,
        onChange: (keys: Key[]) => setSelectedRowKeys(keys),
      };
      const [dataSource, setDataSource] = useState<any[]>([...data] as any[]);
    
      return (
        <>
          <ProList<{
            title: string;
            subTitle: React.JSX.Element;
            actions: React.JSX.Element[];
            description: React.JSX.Element;
            type?: 'top' | 'inline' | 'new';
            avatar: string;
            children: React.JSX.Element;
          }>
            columns={[
              { dataIndex: 'title', listSlot: 'title' },
              { dataIndex: 'subTitle', listSlot: 'subTitle' },
              { dataIndex: 'type', listSlot: 'type' },
              { dataIndex: 'description', listSlot: 'description' },
              { dataIndex: 'avatar', listSlot: 'avatar' },
              { dataIndex: 'content', listSlot: 'content' },
              { dataIndex: 'actions', listSlot: 'actions' },
            ]}
            toolBarRender={() => [
              <Button
                key="3"
                type="primary"
                onClick={() => {
                  setDataSource([...data.map((item) => ({ ...item }))]);
                  setTimeout(() => {
                    const list = [...data.map((item) => ({ ...item }))];
                    list[1].type = 'new';
                    setDataSource(list);
                  }, 0);
                }}
              >
                刷新
              </Button>,
            ]}
            rowKey="id"
            headerTitle="预设的列状态"
            rowSelection={rowSelection}
            dataSource={dataSource}
            expandable={{
              expandedRowKeys,
              onExpandedRowsChange: setExpandedRowKeys,
            }}
          />
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Pagination

    翻页

    智慧零售平台
    技术专栏

    发布中
    80%

    Ant Design Pro
    技术专栏

    发布中
    80%

    云原生微服务框架
    技术专栏

    发布中
    80%

    数据可视化引擎
    技术专栏

    发布中
    80%

    智能客服系统
    技术专栏

    发布中
    80%
    • 第 1-5 条/总共 7 条
    • 1
    • 2
    import { EllipsisOutlined } from '@ant-design/icons';
    import { ProList } from '@ant-design/pro-components';
    import { Progress, Tag } from 'antd';
    
    const data = [
      '智慧零售平台',
      'Ant Design Pro',
      '云原生微服务框架',
      '数据可视化引擎',
      '智能客服系统',
      'DevOps 工具链',
      '统一权限管理中心',
    ].map((item) => ({
      title: item,
      subTitle: <Tag color="#5BD8A6">技术专栏</Tag>,
      actions: [
        <a key="invite">邀请</a>,
        <a key="operate">操作</a>,
        <a key="rest">
          <EllipsisOutlined />
        </a>,
      ],
      avatar:
        'https://gw.alipayobjects.com/zos/antfincdn/UCSiy1j6jx/xingzhuang.svg',
      content: (
        <div
          style={{
            flex: 1,
            display: 'flex',
            justifyContent: 'flex-end',
          }}
        >
          <div
            style={{
              width: 200,
            }}
          >
            <div>发布中</div>
            <Progress percent={80} />
          </div>
        </div>
      ),
    }));
    
    const Demo = () => {
      return (
        <ProList<any>
          pagination={{
            defaultPageSize: 5,
            showSizeChanger: true,
          }}
          columns={[
            { dataIndex: 'title', listSlot: 'title' },
            { dataIndex: 'subTitle', listSlot: 'subTitle' },
            { dataIndex: 'type', listSlot: 'type' },
            { dataIndex: 'avatar', listSlot: 'avatar' },
            { dataIndex: 'content', listSlot: 'content' },
            { dataIndex: 'actions', listSlot: 'actions' },
          ]}
          headerTitle="翻页"
          dataSource={data}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Custom list item (itemRender)

    Use itemRender to customize each item's rendering. The third argument defaultDom is the default list item element (React.ReactElement); you can wrap it or replace it.

    帆软 SSO
    FineReport 是一款用于报表制作、分析和展示的软件,支持数据填报与可视化大屏。
    泛微 E9 SSO
    泛微 E9 是一款成熟的协同办公软件,以流程管理、知识管理为核心。
    销售易
    SAML (Security Assertion Markup Language) 是一种用于身份认证与授权的标准协议。
    import { ProList } from '@ant-design/pro-components';
    import { Avatar, theme } from 'antd';
    
    const APPLICATIONS = [
      {
        id: '1',
        title: '帆软 SSO',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/UCSiy1j6jx/xingzhuang.svg',
        description:
          'FineReport 是一款用于报表制作、分析和展示的软件,支持数据填报与可视化大屏。',
      },
      {
        id: '2',
        title: '泛微 E9 SSO',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/UCSiy1j6jx/xingzhuang.svg',
        description:
          '泛微 E9 是一款成熟的协同办公软件,以流程管理、知识管理为核心。',
      },
      {
        id: '3',
        title: '销售易',
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/UCSiy1j6jx/xingzhuang.svg',
        description:
          'SAML (Security Assertion Markup Language) 是一种用于身份认证与授权的标准协议。',
      },
    ];
    
    type AppItem = (typeof APPLICATIONS)[0];
    
    export default () => {
      const { token } = theme.useToken();
      return (
        <div
          style={{
            backgroundColor: token.colorBgLayout,
            margin: -24,
            padding: 64,
          }}
        >
          <ProList<AppItem>
            rowKey="id"
            split
            grid={{
              xs: 1,
              sm: 2,
              md: 2,
              lg: 4,
              xl: 4,
              xxl: 4,
              gutter: [16, 16],
            }}
            pagination={false}
            columns={[
              { dataIndex: 'title', listSlot: 'title' },
              { dataIndex: 'avatar', listSlot: 'avatar' },
              { dataIndex: 'description', listSlot: 'description' },
            ]}
            dataSource={APPLICATIONS}
            toolbar={{
              menu: {
                type: 'tab',
                items: [
                  { key: 'all', label: '全部应用' },
                  { key: 'dev', label: '开发类' },
                  { key: 'ops', label: '运维类' },
                  { key: 'office', label: '办公类' },
                ],
              },
            }}
            itemRender={(item) => (
              <div
                style={{
                  width: '100%',
                  minWidth: 0,
                  boxSizing: 'border-box',
                  borderRadius: 8,
                  padding: 24,
                  height: '100%',
                  cursor: 'pointer',
                  boxShadow: '0 1px 2px rgba(0,0,0,0.03)',
                  background: token.colorBgContainer,
                }}
                tabIndex={0}
              >
                <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
                  <Avatar
                    src={item.avatar}
                    shape="square"
                    size={48}
                    style={{ flexShrink: 0 }}
                  />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div
                      style={{
                        fontWeight: 600,
                        fontSize: 16,
                        marginBottom: 4,
                      }}
                    >
                      {item.title}
                    </div>
                    <div
                      style={{
                        color: token.colorTextSecondary,
                        fontSize: 14,
                        lineHeight: 1.5,
                        overflow: 'hidden',
                        textOverflow: 'ellipsis',
                        display: '-webkit-box',
                        WebkitLineClamp: 2,
                        WebkitBoxOrient: 'vertical',
                      }}
                    >
                      {item.description}
                    </div>
                  </div>
                </div>
              </div>
            )}
          />
        </div>
      );
    };
    

    API

    ProList is built on top of ProTable and supports two column configuration approaches:

    • columns + listSlot (Recommended): Shares the same columns array with ProTable. Use listSlot to specify which slot of the list item each column maps to. The same columns can be used for both ProTable and ProList, making it easy to switch between table and list views.
    • metas (Deprecated): The legacy configuration using object keys to map list item parts. Still functional but migration to columns + listSlot is recommended.

    For other APIs, refer to ProTable.

    request

    request is the most important API of ProList, identical to ProTable's usage. request receives an object that must contain data and success; total is also required for manual pagination. request takes over loading management and re-executes when the search form is submitted or params change.

    <ProList<DataType, Params>
      params={params}
      request={async (params, sort, filter) => {
        const msg = await myQuery({
          page: params.current,
          pageSize: params.pageSize,
        });
        return {
          data: msg.result,
          success: true,
          total: msg.total,
        };
      }}
    />

    ProList

    PropertyDescriptionTypeDefault
    columnsColumn configuration, same as ProTable. Use listSlot to specify list item slots. See columns ConfigurationProColumns<T>[]-
    metasDeprecated List item configuration, see Metas Configuration. Please migrate to columns + listSlotMetas-
    dataSourceSame configuration as antd. ProList recommends using request to load dataT[]-
    requestMethod to get dataSource(params: U & { pageSize?: number; current?: number; keyword?: string }, sort: Record<string, SortOrder>, filter: Record<string, FilterValue>) => Promise<{ data: T[]; success?: boolean; total?: number }>-
    paramsExtra parameters for request query, triggers reload on changeU-
    postDataProcess data obtained through request(data: T[]) => T[]-
    defaultDataDefault dataT[]-
    onDataSourceChangeTriggered when data changes(dataSource: T[]) => void-
    actionRefTable action reference for custom triggeringReact.Ref<ActionType | undefined>-
    formRefGet the form instance of the search formTableFormItem<T>['formRef']-
    rowKeyRow key, usually row id; falls back to item.key then index when unsetkeyof T | (item: T) => React.Key-
    headerTitleTitle on the top leftReactNode-
    tooltipTooltip next to the titlestring | LabelTooltipType-
    loadingWhether loadingboolean | { spinning?: boolean }false
    splitWhether to show a split linebooleantrue
    variantList appearance variant'outlined' | 'borderless' | 'filled''borderless'
    showActionsWhen to show the actions area. 'hover' shows actions when hovering or focusing the list item'hover' | 'always''always'
    showExtraWhen to show the extra area (the aside slot). 'hover' shows it only when hovering the list item. Not supported in CardList mode'hover' | 'always''always'
    footerList footerReactNode-
    gridGrid configuration, enables card mode when setListGridType-
    itemLayoutList item layout direction'horizontal' | 'vertical''horizontal'
    localeInternationalization configuration{ emptyText?: ReactNode }-
    paginationPagination configuration, current and pageSize are managed by requestPaginationConfig | falsefalse
    rowSelectionRow selection configurationTableProps<T>['rowSelection'] & { alwaysShowAlert?: boolean } | falsefalse
    expandableSame configuration as antdobject | false-
    onRowSame configuration as antd. When grid is set, the list renders in card mode and this event will not fire. Use onItem insteadfunction(record, index)-
    onItemSame configuration as antd. Clicking on an item in all types will trigger this eventfunction(record, index)-
    itemRenderCustom list item render. defaultDom is the default list item element. Wrap or replace it(item: T, index: number, defaultDom: React.ReactElement) => ReactNode-
    rowClassNameCustom list row class namestring | (item: T, index: number) => string-
    itemHeaderRenderCustomize the header of each item. Different from itemRender, it preserves multi-select and expand/collapse((item: T, index: number, defaultDom: JSX.Element | null) => ReactNode) | false-
    itemTitleRenderCustomize the title rendering of each item((item: T, index: number, defaultDom: JSX.Element | null) => ReactNode) | false-
    itemCardPropsCustom card list props, only valid in card modeCheckCardProps-
    toolBarRenderRender toolbar, supports returning an array of dom, automatically adds margin-rightToolBarProps<T>['toolBarRender'] | false-
    searchWhether to show the search form, pass an object for search form configurationfalse | SearchConfigfalse
    onLoadTriggered after data loading is complete, may fire multiple times(dataSource: T[]) => void-
    onLoadingChangeTriggered when loading changes, usually caused by network requests(loading: boolean | SpinProps | undefined) => void-
    onRequestErrorTriggered when data loading fails(error: Error) => void-
    onSubmitTriggered when the form is submitted(params: U) => void-
    onResetTriggered when the form is reset() => void-
    cardPropsCard settings for the outer wrapperProCardProps | false-
    editableEditable list configuration, see Editable TableRowEditableConfig<T>-
    manualRequestWhether to manually trigger the first requestbooleanfalse
    ghostGhost mode, removes padding from the areabooleanfalse
    dateFormatterConvert dayjs format data to a specific type, false to skip conversion"string" | "number" | ((value: dayjs.Dayjs, valueType: string) => string | number) | false"string"
    ErrorBoundaryBuilt-in error handling to prevent blank screens, ErrorBoundary=false disables itReact.ComponentClass<any, any> | falseBuilt-in ErrorBoundary

    ActionRef

    Sometimes you need to manually trigger ProList's reload and other operations. Use actionRef, which works identically to ProTable ActionRef.

    MethodDescriptionType
    reloadReload the list, pass true to reset page index(resetPageIndex?: boolean) => Promise<void>
    reloadAndRestReload and clear, page index is also reset, excluding the form() => Promise<void>
    resetReset to default values, including the form() => void
    clearSelectedClear selected items() => void
    startEditableStart editing a row(rowKey: Key) => boolean
    cancelEditableCancel editing a row(rowKey: Key) => boolean
    const ref = useRef<ActionType>();
    
    <ProList actionRef={ref} />;
    
    // Reload
    ref.current?.reload();
    
    // Reload and clear, page index is also reset, excluding the form
    ref.current?.reloadAndRest();
    
    // Reset to default values, including the form
    ref.current?.reset();
    
    // Clear selected items
    ref.current?.clearSelected();

    The same columns can be used for both ProTable (table view) and ProList (list view). ProTable ignores the listSlot property, while ProList uses it to map data to list item slots. Columns without listSlot are not rendered in list items but still participate in search form generation.

    ProList Extended Column Properties

    PropertyDescriptionTypeDefault
    listSlotSpecifies which slot of the list item this column maps to'title' | 'subTitle' | 'avatar' | 'description' | 'content' | 'actions' | 'aside' | 'type'-

    All other column properties are identical to ProTable's ProColumns (dataIndex, valueType, render, search, valueEnum, etc.). See ProTable columns.

    listSlot Slot Reference

    Slot ValueDescriptionDefault valueType
    titleList item titletext
    subTitleList item subtitletext
    avatarList item avataravatar
    descriptionList item descriptiontextarea
    contentList item content areatext
    actionsList item action areaoption
    asideSupplementary side content (e.g. images, progress bars, non-interactive content)text
    typeList item type ('new' | 'top' | 'inline')text

    Usage Example

    import type { ProColumns } from '@ant-design/pro-components';
    
    // Same columns for both ProTable and ProList
    const columns: ProColumns<DataItem>[] = [
      { title: 'Name', dataIndex: 'name', listSlot: 'title' },
      { dataIndex: 'avatar', listSlot: 'avatar', search: false },
      { dataIndex: 'desc', listSlot: 'description', search: false },
      {
        title: 'Labels',
        dataIndex: 'labels',
        listSlot: 'subTitle',
        search: false,
        render: (_, row) => <Tag>{row.label}</Tag>,
      },
      {
        title: 'Actions',
        listSlot: 'actions',
        search: false,
        render: (_, row) => [<a key="edit">Edit</a>],
      },
      {
        title: 'Status',
        dataIndex: 'status',
        valueType: 'select',
        valueEnum: { open: { text: 'Open' }, closed: { text: 'Closed' } },
        // No listSlot — not rendered in list items, search only
      },
    ];
    
    <ProList columns={columns} />  // List view
    <ProTable columns={columns} /> // Table view

    Metas Configuration (Deprecated)

    Deprecated: metas still works but migration to columns + listSlot is recommended. See the Migration Guide below.

    Metas uses object keys to map list item parts (title, avatar, description, etc.) to data fields.

    Metas.[Meta] Generic API

    PropertyDescriptionTypeDefault
    dataIndexThe path corresponding to the data in the data item, supports querying nested paths through an arraystring | string[]-
    titleTitleReactNode-
    valueTypeValue type, same as ProTable, generates different renderersvalueType'text'
    renderCustom render function(text: ReactNode, record: T, index: number) => ReactNode | ReactNode[]-
    valueEnumEnum of values, automatically converts the value as a key to display the corresponding contentvalueEnum-
    searchConfigure search for the column, false to hideboolean | { transform: (value: any) => any }-
    editableWhether editable in editable listboolean | (text: any, record: T, index: number) => boolean-
    fieldPropsProps for the search form, passed to the form item(form, config) => Record | Record-
    formItemPropsConfiguration passed to Form.Item(form, config) => formItemProps | formItemProps-
    formItemRenderRender the input component of the search form(item, { type, defaultRender, formItemProps, fieldProps, ...rest }, form) => ReactNode-
    keyReact keyReact.Key-

    Metas.type

    The field type corresponding to dataSource is 'new' | 'top' | 'inline'.

    PropertyDescriptionTypeDefault
    dataIndex--'type'

    Metas.title

    PropertyDescriptionTypeDefault
    dataIndex--'title'

    Metas.subTitle

    PropertyDescriptionTypeDefault
    dataIndex--'subTitle'

    Metas.description

    PropertyDescriptionTypeDefault
    dataIndex--'description'

    Metas.avatar

    PropertyDescriptionTypeDefault
    dataIndex--'avatar'

    Metas.actions

    PropertyDescriptionTypeDefault
    dataIndex--'actions'

    Metas.content

    PropertyDescriptionTypeDefault
    dataIndex--'content'

    Only type, title, subTitle, description, avatar, content and actions keys are supported in metas. The Metas.extra documented previously does not exist in the type definitions; for aside content use listSlot: 'aside' in columns (mapped internally to the list item's extra area).

    Batch operations

    Same as ProTable, batch operations require setting rowSelection. See ProTable Batch Operations for details.

    PropertyDescriptionTypeDefault
    alwaysShowAlertAlways show alert, hidden by default when nothing is selected (built-in property of rowSelection)boolean-
    tableAlertRenderCustom left info area of the batch operation toolbar, false to hide({ selectedRowKeys: Key[], selectedRows: T[], onCleanSelected: () => void }) => ReactNode) | false-
    tableAlertOptionRenderCustom right options area of the batch operation toolbar, false to hide({ selectedRowKeys: Key[], selectedRows: T[], onCleanSelected: () => void }) => ReactNode) | false-

    Search Form

    ProList generates a search form based on fields with search configured in columns or metas. Usage is identical to ProTable Search Form.

    Migrating from metas to columns

    metas is deprecated. Migration to columns + listSlot is straightforward: convert each key-value pair in the metas object to an element in the columns array, where the key becomes the listSlot and the value's properties are spread into the column configuration.

    Migration Reference

    metas syntaxcolumns syntax
    title: { dataIndex: 'name' }{ dataIndex: 'name', listSlot: 'title' }
    avatar: { dataIndex: 'img' }{ dataIndex: 'img', listSlot: 'avatar' }
    description: { dataIndex: 'desc' }{ dataIndex: 'desc', listSlot: 'description' }
    content: {}{ dataIndex: 'content', listSlot: 'content' }
    extra: { render: ... }{ listSlot: 'aside', render: ... }
    status: { title: 'Status', valueType: 'select', ... }{ title: 'Status', dataIndex: 'status', valueType: 'select', ... }

    Full Example

    Before (metas):

    <ProList
      metas={{
        title: { dataIndex: 'name', title: 'Name' },
        avatar: { dataIndex: 'avatar', search: false },
        description: { dataIndex: 'desc', search: false },
        subTitle: {
          dataIndex: 'labels',
          render: (_, row) => <Tag>{row.label}</Tag>,
          search: false,
        },
        actions: {
          render: (_, row) => [<a key="edit">Edit</a>],
          search: false,
        },
        status: {
          title: 'Status',
          valueType: 'select',
          valueEnum: { open: { text: 'Open' }, closed: { text: 'Closed' } },
        },
      }}
    />

    After (columns + listSlot):

    <ProList
      columns={[
        { title: 'Name', dataIndex: 'name', listSlot: 'title' },
        { dataIndex: 'avatar', listSlot: 'avatar', search: false },
        { dataIndex: 'desc', listSlot: 'description', search: false },
        {
          dataIndex: 'labels',
          listSlot: 'subTitle',
          render: (_, row) => <Tag>{row.label}</Tag>,
          search: false,
        },
        {
          listSlot: 'actions',
          render: (_, row) => [<a key="edit">Edit</a>],
          search: false,
        },
        {
          title: 'Status',
          dataIndex: 'status',
          valueType: 'select',
          valueEnum: { open: { text: 'Open' }, closed: { text: 'Closed' } },
        },
      ]}
    />

    Tip: After migration, the same columns can be passed directly to ProTable for a one-click switch between list and table views.