The Advanced Table also allows for rendering custom components within individual Cells. To achieve this, you can make use of the optional customRenderer item within each columnDefinition. This function gives you access to the current Cell's value if you just want to use that with a custom Kit, but it also gives you access to the entire row object. The row object provides all data for the current row. To access the data, use row.original which is the entire data object for the current row. See the code snippet below for 3 separate use cases and how they were acheived.
See here for more indepth information on columnDefinitions are how to use them.
See here for the structure of the tableData used.
import React from "react" import { AdvancedTable, Pill, Body, Flex, Detail, Caption, Badge, Title } from 'playbook-ui' import MOCK_DATA from "./advanced_table_mock_data.json" const AdvancedTableCustomCell = (props) => { const columnDefinitions = [ { accessor: "year", label: "Year", cellAccessors: ["quarter", "month", "day"], customRenderer: (row, value) => ( <Flex> <Title size={4} text={value} /> <Badge dark marginLeft="xxs" text={row.original.newEnrollments > 20 ? "High" : "Low"} variant="neutral" /> </Flex> ), }, { accessor: "newEnrollments", label: "New Enrollments", customRenderer: (row, value) => ( <Pill text={value} variant="success" /> ), }, { accessor: "scheduledMeetings", label: "Scheduled Meetings", customRenderer: (row, value) => <Body><a href="#">{value}</a></Body>, }, { accessor: "attendanceRate", label: "Attendance Rate", customRenderer: (row, value) => ( <Flex alignItems="end" orientation="column" > <Detail bold color="default" text={value} /> <Caption size="xs">{row.original.graduatedStudents}</Caption> </Flex> ), }, { accessor: "completedClasses", label: "Completed Classes", }, { accessor: "classCompletionRate", label: "Class Completion Rate", }, { accessor: "graduatedStudents", label: "Graduated Students", }, ] return ( <div> <AdvancedTable columnDefinitions={columnDefinitions} enableToggleExpansion="all" responsive="none" tableData={MOCK_DATA} > <AdvancedTable.Header enableSorting /> <AdvancedTable.Body /> </AdvancedTable> </div> ) } export default AdvancedTableCustomCell
The optional header key/value pair can be used within columnDefinitions to render a custom header. This example shows an Icon and Tooltip being used but other kits can be used as well.
import React from "react" import { AdvancedTable, Icon, Flex, Caption, Tooltip } from 'playbook-ui' import MOCK_DATA from "./advanced_table_mock_data.json" const AdvancedTableWithCustomHeader = (props) => { const columnDefinitions = [ { accessor: "year", label: "Year", cellAccessors: ["quarter", "month", "day"], }, { accessor: "newEnrollments", label: "New Enrollments", header: () => ( <Flex alignItems="center" justifyContent="center" > <Caption marginRight="xs">New Enrollments</Caption> <Tooltip placement="top" text="Whoa. I'm a Tooltip" zIndex={10} > <Icon cursor="pointer" icon="info" size="xs" /> </Tooltip> </Flex> ), }, { accessor: "scheduledMeetings", label: "Scheduled Meetings", }, { accessor: "attendanceRate", label: "Attendance Rate", }, { accessor: "completedClasses", label: "Completed Classes", }, { accessor: "classCompletionRate", label: "Class Completion Rate", }, { accessor: "graduatedStudents", label: "Graduated Students", }, ]; return ( <div> <AdvancedTable columnDefinitions={columnDefinitions} tableData={MOCK_DATA} /> </div> ) } export default AdvancedTableWithCustomHeader
The optional header key/value pair within columnDefinitions can also be used with multi headers as seen here.
import React from "react" import { AdvancedTable, Icon, Flex, Caption, Tooltip } from 'playbook-ui' import MOCK_DATA from "./advanced_table_mock_data.json" const AdvancedTableWithCustomHeaderMultiHeader = (props) => { const columnDefinitions = [ { accessor: "year", label: "Year", id: "year", cellAccessors: ["quarter", "month", "day"], }, { label: "Enrollment Data", id: "enrollmentData", header: () => ( <Flex alignItems="center" justifyContent="center" > <Caption marginRight="xs">Enrollments Data</Caption> <Tooltip placement="top" text="Whoa. I'm a Tooltip" zIndex={10} > <Icon cursor="pointer" icon="info" size="xs" /> </Tooltip> </Flex> ), columns: [ { label: "Enrollment Stats", id: "enrollmentStats", columns: [ { accessor: "newEnrollments", id: "newEnrollments", label: "New Enrollments", }, { accessor: "scheduledMeetings", id: "scheduledMeetings", label: "Scheduled Meetings", }, ], }, ], }, { label: "Performance Data", id: "performanceData", columns: [ { label: "Completion Metrics", id: "completionMetrics", columns: [ { accessor: "completedClasses", label: "Completed Classes", id: "completedClasses", }, { accessor: "classCompletionRate", label: "Class Completion Rate", id: "classCompletionRate", }, ], }, { label: "Attendance", id: "attendance", header: () => ( <Flex alignItems="center" justifyContent="center" > <Caption marginRight="xs">Attendance</Caption> <Tooltip placement="top" text="Whoa. I'm a Tooltip Too!" zIndex={10} > <Icon cursor="pointer" icon="info" size="xs" /> </Tooltip> </Flex> ), columns: [ { accessor: "attendanceRate", label: "Attendance Rate", id: "attendanceRate", }, { accessor: "scheduledMeetings", label: "Scheduled Meetings", id: "scheduledMeetings", }, ], }, ], }, ]; return ( <div> <AdvancedTable columnDefinitions={columnDefinitions} tableData={MOCK_DATA} /> </div> ) } export default AdvancedTableWithCustomHeaderMultiHeader;
Inline Cell Editing can be achieved with a combination of our TextInput kit and the customRenderer method available through columnDefinitions.
Hover over any cell within the 'Scheduled Meetings' column to see the TextInput and type in to change values. Values can be saved by clicking away from the TextInput or by hitting 'Enter'.
See the code snippet below to see how this was achieved. Devs must manage state themselves as shown.
import React, { useState } from "react"; import { AdvancedTable, TextInput, Body } from 'playbook-ui' import MOCK_DATA from "./advanced_table_mock_data.json"; const AdvancedTableInlineEditing = (props) => { const [editedValues, setEditedValues] = useState({}); const EditableCell = ({ rowId, originalValue, onSave }) => { const [localValue, setLocalValue] = useState(originalValue); const handleChange = (e) => setLocalValue(e.target.value); const handleBlur = () => { originalValue !== localValue && onSave(rowId, localValue); }; return ( <TextInput inline marginBottom="none" > <input onBlur={handleBlur} onChange={handleChange} onKeyDown={(e) => e.key === 'Enter' && handleBlur()} value={localValue} /> </TextInput> ); }; const columnDefinitions = [ { accessor: "year", label: "Year", cellAccessors: ["quarter", "month", "day"], }, { accessor: "newEnrollments", label: "New Enrollments", }, { accessor: "scheduledMeetings", label: "Scheduled Meetings", editable: true, customRenderer: (row) => { return ( <EditableCell onSave={(id, val) => { setEditedValues((prev) => ({ ...prev, [id]: val })); }} originalValue={ editedValues[row.id] ?? row.original.scheduledMeetings } rowId={row.id} /> ); }, }, { accessor: "attendanceRate", label: "Attendance Rate", }, { accessor: "completedClasses", label: "Completed Classes", }, { accessor: "classCompletionRate", label: "Class Completion Rate", }, { accessor: "graduatedStudents", label: "Graduated Students", }, ]; return ( <div className="App"> <AdvancedTable columnDefinitions={columnDefinitions} tableData={MOCK_DATA} /> { editedValues && Object.keys(editedValues).length > 0 && ( <> <Body marginTop="md" > Edited Values by Row Id: </Body> <pre style={{color: 'white'}}>{JSON.stringify(editedValues, null, 2)}</pre> </> ) } </div> ); }; export default AdvancedTableInlineEditing;