Control Layout
Control Layout enables users to curate data by performing actions, searching, filtering, and manipulating display results for Table, DataCardList, and DataGrid. This component is built into DataView.
Item | Name | Description |
---|---|---|
A | <Autocomplete /> or<TextField /> | Both<Autocomplete /> and <TextField /> allows users to search for results within the datasetUse <Autocomplete /> when displaying a <Menu /> with suggestionsUse <TextField /> when the API can not support displaying a <Menu /> with suggestions |
B | <Checkbox /> | The <Checkbox /> gives users the option to select all items displayed within a dataset |
C | <Button /> | The <Button /> gives users the option to perform an action on the selected items within a dataset |
D | <Button /> | The <Button /> gives users the option to filter results within a dataset |
E | <Button /> | The <Button /> gives users the option to manipulate display options with the <DataView /> |
Select row | Name | Department | Job Title | Email address |
---|---|---|---|---|
Liana Varo | Marketing | Contractor | ||
Henry Cote | Human Resources | Engineer | ||
Maria Stephens | Marketing | Chief Editor | ||
Mark Brouwer | Accounting and Finance | People Operations | ||
Tatiana Robu | R&D | Designer | ||
Ruby Nguyen | Sales | Sr. Engineer | ||
Sergio Guevara | Sales | Account Manager | ||
Rafe Walker | Accounting and Finance | Information Security Specialist | ||
Fabian Lupea | Legal | Office Operations | ||
Sienna Brown | Operations | CTO | ||
Zoe Mordin | Marketing | Recruiter | ||
Vinay Katwal | Purchasing | Account Director | ||
Charlie King | IT | Project Manager | ||
Maria Mancini | Marketing | Client Support Manager | ||
Dorothy Bishop | IT | Marketing Director | ||
Victor Dubois | Sales | Recruiter | ||
Phillip Carroll | Sales | Client Support Director | ||
Willie Morrison | Security | Level 1 Tech Suport | ||
Liam Jones | Employee | Associate Creative Director | ||
Felix Roth | Human Resources | Contractor | ||
Noah Anderson | Accounting and Finance | Engineer | ||
Sienna Smith | Operations | Sr. Designer | ||
Craig Ellis | Legal | Office Administrator | ||
Rosa Amador | Sales | Client Support Manager | ||
Alexis Muller | IT | IT Specialist | ||
Jasmine Jacob | Human Resources | IT Ops Lead | ||
Emily Lee | Legal | CEO |
import React from 'react'import {Box,Button,Checkbox,CheckboxGroup,ControlLayout,DataGrid,DataGridBody,DataGridDataCell,DataGridHeader,DataGridHeaderCell,DataGridRow,DataGridSelectRowDataCell,DataGridSelectRowHeaderCell,Dialog,DialogActions,DialogBody,DialogFooter,DialogHeader,Link,Menu,MenuItem,Pagination,PaginationNavigation,PaginationNavigationButton,PaginationPerPageSelectField,TextField,useDialog,useMenu,} from '@gusto/workbench'import { CaretDown, Filter, Search } from '@gusto/workbench-icons'import { employees } from './_employees'export const Basic = () => {// default "columns" checkbox set on page loadconst defaultColumnsOptions = ['name','department','jobTitle','emailAddress',]// default filters and their selection on page loadconst defaultFilterNames = {Department: [],Title: [],}// Menu props for the actionsMenu and filterColumnsMenu in `sm` breakpointconst [actionsMenuProps, actionsMenuButtonProps] = useMenu()// filter and "columns" Dialog 'open' stateconst [filtersDialogProps, filtersDialogButtonProps] = useDialog()const [columnsDialogProps, columnsDialogButtonProps] = useDialog()const [rowSelected, setRowSelected] = React.useState<{[key: number]: boolean}>({})// used to keep track of the onChange of the "columns" checkboxes in columnsDialogconst [columnsCheckboxChecked, setColumnsCheckboxChecked] = React.useState<string[]>(defaultColumnsOptions)// used to make changes to the table on "Apply" of the filters dialogconst [columnsDisplayed, setColumnsDisplayed] = React.useState<string[]>(defaultColumnsOptions,)// used to keep track of the onChange of the filter checkboxesconst [filterCheckboxChecked, setFilterCheckboxChecked] = React.useState<{[key: string]: string[]}>(defaultFilterNames)// used to make changes to the table on "Apply" of the filters dialogconst [appliedFilterCheckboxes, setAppliedFilterCheckboxes] = React.useState<{[key: string]: string[]}>(defaultFilterNames)// used to determine filter count, if filters are applied, and filters dataconst filterCount =appliedFilterCheckboxes.Department.length +appliedFilterCheckboxes.Title.lengthconst isDataFiltered =appliedFilterCheckboxes.Department.length > 0 ||appliedFilterCheckboxes.Title.length > 0const filteredEmployees = isDataFiltered? employees.filter(employee => {return (appliedFilterCheckboxes.Department.includes(employee.Department) ||appliedFilterCheckboxes.Title.includes(employee.Title))}): employees// used to determine if the "select all" checkbox is checked, indeterminate, or uncheckedconst rowSelectedCount = Object.values(rowSelected).filter(val => val).lengthconst selectAllChecked = rowSelectedCount === filteredEmployees.lengthconst selectAllIndeterminate = rowSelectedCount > 0 && !selectAllChecked// an example of keeping track of rows selectedconst toggleGridRowSelection = (id: number) => {setRowSelected(currSelected => ({...currSelected,[id]: !rowSelected[id],}))}// an example of creating the "select all" functionalityconst toggleAllRows = () => {employees.map(employee => employee.Digit).forEach(digit => {setRowSelected(currRowsSelected => ({...currRowsSelected,[digit]: !selectAllChecked,}))})}// an example of keeping a state management of each columns checkbox being checkedconst columnsCheckboxOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {const checkboxChecked = e.target.checkedif (checkboxChecked) {setColumnsCheckboxChecked(currChecked => [...currChecked, e.target.value])} else {setColumnsCheckboxChecked(currChecked =>currChecked.filter(value => value !== e.target.value),)}}// an example of resetting columns optionsconst resetColumnsOptions = () => {setColumnsCheckboxChecked(defaultColumnsOptions)}// an example of updating the visibility of columnsconst updateColumnVisibility = () => {setColumnsDisplayed(columnsCheckboxChecked)}// an example of keeping a state management of each filter checkbox being checkedconst filterCheckboxOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {// getting the group name from CheckboxGroupconst groupName = e.target.nameconst checkboxChecked = e.target.checkedif (checkboxChecked) {setFilterCheckboxChecked(currChecked => ({...currChecked,[groupName]: [...currChecked[groupName], e.target.value],}))} else {setFilterCheckboxChecked(currChecked => ({...currChecked,[groupName]: currChecked[groupName].filter(value => value !== e.target.value,),}))}}// an example of applying filters on "apply" button submit within filters Dialogconst applyFilters = () => {filtersDialogProps.onClose()setAppliedFilterCheckboxes(filterCheckboxChecked)}// an example of resetting filters within the filters Dialogconst resetFilters = () => {setFilterCheckboxChecked(defaultFilterNames)}return (<><ControlLayoutsearchField={<TextFieldlabel="Search"before={<Search />}placeholder="Search"visuallyHideLabel/>}selectAllCheckbox={<Checkboxtype="checkbox"label={rowSelectedCount > 0? `${rowSelectedCount} Selected`: `Select all (${filteredEmployees.length})`}checked={selectAllChecked}indeterminate={selectAllIndeterminate}onChange={toggleAllRows}/>}selectAllActionsMenu={selectAllChecked || selectAllIndeterminate ? (<><Button{...actionsMenuButtonProps}after={<CaretDown />}size="small"variant="primary">Actions</Button><Menu{...actionsMenuProps}aria-label="Employee information actions menu"><MenuItem>Lorem ipsum</MenuItem><MenuItem>Lorem ipsum</MenuItem></Menu></>) : null}actions={<><Buttonvariant="tertiary"size="small"before={<Filter />}{...filtersDialogButtonProps}>Filter{filterCount > 0 ? ` (${filterCount})` : null}</Button><Buttonvariant="tertiary"size="small"{...columnsDialogButtonProps}>Columns</Button><Dialogaria-label="Employee information filters"{...filtersDialogProps}><DialogHeader>Filters</DialogHeader><DialogBody><Box marginBottom={6}><CheckboxGroup name="Department" legend="Departments">{Array.from(new Set(employees.map(employee => employee.Department)),).map(department => {return (<Checkboxkey={`emp-type-checkbox-${department}`}value={department}label={department}checked={filterCheckboxChecked.Department.includes(department,)}onChange={filterCheckboxOnChange}/>)})}</CheckboxGroup></Box><Box marginBottom={6}><CheckboxGroup name="Title" legend="Job title">{Array.from(new Set(employees.map(employee => employee.Title)),).map(title => {return (<Checkboxkey={`emp-type-checkbox-${title}`}value={title}label={title}checked={filterCheckboxChecked.Title.includes(title)}onChange={filterCheckboxOnChange}/>)})}</CheckboxGroup></Box></DialogBody><DialogFooter><DialogActions><Button variant="primary" onClick={applyFilters}>Apply</Button><Button onClick={resetFilters}>Clear all filters</Button></DialogActions></DialogFooter></Dialog><Dialogaria-label="Employee information visible columns"{...columnsDialogProps}><DialogHeader>Columns</DialogHeader><DialogBody><CheckboxGroupname="columnsOptions"legend="Column options"visuallyHideLabel><Checkboxvalue="name"label="Name"checked={columnsCheckboxChecked.includes('name')}onChange={columnsCheckboxOnChange}/><Checkboxvalue="department"label="Department"checked={columnsCheckboxChecked.includes('department')}onChange={columnsCheckboxOnChange}/><Checkboxvalue="jobTitle"label="Job title"checked={columnsCheckboxChecked.includes('jobTitle')}onChange={columnsCheckboxOnChange}/><Checkboxvalue="emailAddress"label="Email address"checked={columnsCheckboxChecked.includes('emailAddress')}onChange={columnsCheckboxOnChange}/></CheckboxGroup></DialogBody><DialogFooter><DialogActions><Buttonvariant="primary"onClick={() => {columnsDialogProps.onClose()updateColumnVisibility()}}>Apply</Button><Button onClick={resetColumnsOptions}>Reset</Button></DialogActions></DialogFooter></Dialog></>}/><DataGridaria-label="Employee information"gridSectionStyles={{ maxHeight: '50rem' }}><DataGridHeader><DataGridRow><DataGridSelectRowHeaderCell />{columnsDisplayed.includes('name') && (<DataGridHeaderCell>Name</DataGridHeaderCell>)}{columnsDisplayed.includes('department') && (<DataGridHeaderCell>Department</DataGridHeaderCell>)}{columnsDisplayed.includes('jobTitle') && (<DataGridHeaderCell>Job Title</DataGridHeaderCell>)}{columnsDisplayed.includes('emailAddress') && (<DataGridHeaderCell>Email address</DataGridHeaderCell>)}</DataGridRow></DataGridHeader><DataGridBody>{filteredEmployees.map(employee => {return (<DataGridRowkey={`emp-${employee.Digit}`}rowSelected={rowSelected[employee.Digit]}><DataGridSelectRowDataCelllabel={`Select row ${employee['Name-FL']}`}checked={rowSelected[employee.Digit] || false}onChange={() => toggleGridRowSelection(employee.Digit)}/>{columnsDisplayed.includes('name') && (<DataGridHeaderCell scope="row"><Link href="https://gusto.com">{employee['Name-FL']}</Link></DataGridHeaderCell>)}{columnsDisplayed.includes('department') && (<DataGridDataCell>{employee.Department}</DataGridDataCell>)}{columnsDisplayed.includes('jobTitle') && (<DataGridDataCell>{employee.Title}</DataGridDataCell>)}{columnsDisplayed.includes('emailAddress') && (<DataGridDataCell><TextFieldlabel="Email address"visuallyHideLabelvalue={employee.Email}readOnly/></DataGridDataCell>)}</DataGridRow>)})}</DataGridBody></DataGrid><Paginationposition="sticky"aria-label="Employee information table"variant="joined"><PaginationPerPageSelectField /><PaginationNavigation><PaginationNavigationButton variant="first" /><PaginationNavigationButton variant="previous" /><PaginationNavigationButton variant="next" /><PaginationNavigationButton variant="last" /></PaginationNavigation></Pagination></>)}
- NameLiana Varo
- DepartmentMarketing
- Job titleContractor
- NameHenry Cote
- DepartmentHuman Resources
- Job titleEngineer
- NameMaria Stephens
- DepartmentMarketing
- Job titleChief Editor
- NameMark Brouwer
- DepartmentAccounting and Finance
- Job titlePeople Operations
- NameTatiana Robu
- DepartmentR&D
- Job titleDesigner
- NameRuby Nguyen
- DepartmentSales
- Job titleSr. Engineer
- NameSergio Guevara
- DepartmentSales
- Job titleAccount Manager
- NameRafe Walker
- DepartmentAccounting and Finance
- Job titleInformation Security Specialist
- NameFabian Lupea
- DepartmentLegal
- Job titleOffice Operations
- NameSienna Brown
- DepartmentOperations
- Job titleCTO
- NameZoe Mordin
- DepartmentMarketing
- Job titleRecruiter
- NameVinay Katwal
- DepartmentPurchasing
- Job titleAccount Director
- NameCharlie King
- DepartmentIT
- Job titleProject Manager
- NameMaria Mancini
- DepartmentMarketing
- Job titleClient Support Manager
- NameDorothy Bishop
- DepartmentIT
- Job titleMarketing Director
- NameVictor Dubois
- DepartmentSales
- Job titleRecruiter
- NamePhillip Carroll
- DepartmentSales
- Job titleClient Support Director
- NameWillie Morrison
- DepartmentSecurity
- Job titleLevel 1 Tech Suport
- NameLiam Jones
- DepartmentEmployee
- Job titleAssociate Creative Director
- NameFelix Roth
- DepartmentHuman Resources
- Job titleContractor
- NameNoah Anderson
- DepartmentAccounting and Finance
- Job titleEngineer
- NameSienna Smith
- DepartmentOperations
- Job titleSr. Designer
- NameCraig Ellis
- DepartmentLegal
- Job titleOffice Administrator
- NameRosa Amador
- DepartmentSales
- Job titleClient Support Manager
- NameAlexis Muller
- DepartmentIT
- Job titleIT Specialist
- NameJasmine Jacob
- DepartmentHuman Resources
- Job titleIT Ops Lead
import React, { useId } from 'react'import {Box,Button,Checkbox,CheckboxGroup,ControlLayout,DataCard,DataCardCheckbox,DataCardList,DataCardRecord,Dialog,DialogActions,DialogBody,DialogFooter,DialogHeader,IconButton,Input,Label,Link,Menu,MenuItem,Pagination,PaginationNavigation,PaginationNavigationButton,PaginationPerPageSelectField,TextField,useDialog,useMenu,} from '@gusto/workbench'import { CaretDown, More, Search } from '@gusto/workbench-icons'import { employees } from './_employees'export const WithDataCard = () => {// default "columns" checkbox set on page loadconst defaultColumnsOptions = ['name','department','jobTitle','emailAddress',]const emailId = useId()// default filters and their selection on page loadconst defaultFilterNames = {Department: [],Title: [],}// Menu props for the actionsMenu and filterColumnsMenu in `sm` breakpointconst [actionsMenuProps, actionsMenuButtonProps] = useMenu()const [filterColumnsMenuProps, filterColumnsMenuButtonProps] = useMenu()// filter and "columns" Dialog 'open' stateconst [filtersDialogProps, filtersDialogButtonProps] = useDialog()const [columnsDialogProps, columnsDialogButtonProps] = useDialog()const [rowSelected, setRowSelected] = React.useState<{[key: number]: boolean}>({})// used to keep track of the onChange of the "columns" checkboxes in columnsDialogconst [columnsCheckboxChecked, setColumnsCheckboxChecked] = React.useState<string[]>(defaultColumnsOptions)// used to make changes to the table on "Apply" of the filters dialogconst [columnsDisplayed, setColumnsDisplayed] = React.useState<string[]>(defaultColumnsOptions,)// used to keep track of the onChange of the filter checkboxesconst [filterCheckboxChecked, setFilterCheckboxChecked] = React.useState<{[key: string]: string[]}>(defaultFilterNames)// used to make changes to the table on "Apply" of the filters dialogconst [appliedFilterCheckboxes, setAppliedFilterCheckboxes] = React.useState<{[key: string]: string[]}>(defaultFilterNames)// used to determine filter count, if filters are applied, and filters dataconst filterCount =appliedFilterCheckboxes.Department.length +appliedFilterCheckboxes.Title.lengthconst isDataFiltered =appliedFilterCheckboxes.Department.length > 0 ||appliedFilterCheckboxes.Title.length > 0const filteredEmployees = isDataFiltered? employees.filter(employee => {return (appliedFilterCheckboxes.Department.includes(employee.Department) ||appliedFilterCheckboxes.Title.includes(employee.Title))}): employees// used to determine if the "select all" checkbox is checked, indeterminate, or uncheckedconst rowSelectedCount = Object.values(rowSelected).filter(val => val).lengthconst selectAllChecked = rowSelectedCount === filteredEmployees.lengthconst selectAllIndeterminate = rowSelectedCount > 0 && !selectAllChecked// an example of keeping track of rows selectedconst toggleSelected = (id: number) => {setRowSelected(currSelected => ({...currSelected,[id]: !rowSelected[id],}))}// an example of creating the "select all" functionalityconst toggleAllRows = () => {employees.map(employee => employee.Digit).forEach(digit => {setRowSelected(currRowsSelected => ({...currRowsSelected,[digit]: !selectAllChecked,}))})}// an example of keeping a state management of each columns checkbox being checkedconst columnsCheckboxOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {const checkboxChecked = e.target.checkedif (checkboxChecked) {setColumnsCheckboxChecked(currChecked => [...currChecked, e.target.value])} else {setColumnsCheckboxChecked(currChecked =>currChecked.filter(value => value !== e.target.value),)}}// an example of resetting columns optionsconst resetColumnsOptions = () => {setColumnsCheckboxChecked(defaultColumnsOptions)}// an example of updating the visibility of columnsconst updateColumnVisibility = () => {setColumnsDisplayed(columnsCheckboxChecked)}// an example of keeping a state management of each filter checkbox being checkedconst filterCheckboxOnChange = (e: React.ChangeEvent<HTMLInputElement>) => {// getting the group name from CheckboxGroupconst groupName = e.target.nameconst checkboxChecked = e.target.checkedif (checkboxChecked) {setFilterCheckboxChecked(currChecked => ({...currChecked,[groupName]: [...currChecked[groupName], e.target.value],}))} else {setFilterCheckboxChecked(currChecked => ({...currChecked,[groupName]: currChecked[groupName].filter(value => value !== e.target.value,),}))}}// an example of applying filters on "apply" button submit within filters Dialogconst applyFilters = () => {filtersDialogProps.onClose()setAppliedFilterCheckboxes(filterCheckboxChecked)}// an example of resetting filters within the filters Dialogconst resetFilters = () => {setFilterCheckboxChecked(defaultFilterNames)}return (<Box maxHeight={840} overflow="auto"><Box maxWidth={490} margin="auto" padding={6}><ControlLayoutsearchField={<TextFieldlabel="Search"before={<Search />}placeholder="Search"visuallyHideLabel/>}selectAllCheckbox={<Checkboxtype="checkbox"label={rowSelectedCount > 0? `${rowSelectedCount} Selected`: `Select all (${filteredEmployees.length})`}checked={selectAllChecked}indeterminate={selectAllIndeterminate}onChange={toggleAllRows}/>}selectAllActionsMenu={selectAllChecked || selectAllIndeterminate ? (<><Button{...actionsMenuButtonProps}after={<CaretDown />}size="small"variant="primary">Actions</Button><Menu{...actionsMenuProps}aria-label="Employee information actions menu"><MenuItem>Lorem ipsum</MenuItem><MenuItem>Lorem ipsum</MenuItem></Menu></>) : null}actions={<><IconButton{...filterColumnsMenuButtonProps}title="More actions"><More /></IconButton><Menu{...filterColumnsMenuProps}aria-label="Employee information filters menu"><MenuItem {...filtersDialogButtonProps}>Filter{filterCount > 0 ? ` (${filterCount})` : null}</MenuItem><MenuItem {...columnsDialogButtonProps}>Columns</MenuItem></Menu><Dialogaria-label="Employee information filters"{...filtersDialogProps}><DialogHeader>Filters</DialogHeader><DialogBody><Box marginBottom={6}><CheckboxGroup name="Department" legend="Departments">{Array.from(new Set(employees.map(employee => employee.Department)),).map(department => {return (<Checkboxkey={`emp-type-checkbox-${department}`}value={department}label={department}checked={filterCheckboxChecked.Department.includes(department,)}onChange={filterCheckboxOnChange}/>)})}</CheckboxGroup></Box><Box marginBottom={6}><CheckboxGroup name="Title" legend="Job title">{Array.from(new Set(employees.map(employee => employee.Title)),).map(title => {return (<Checkboxkey={`emp-type-checkbox-${title}`}value={title}label={title}checked={filterCheckboxChecked.Title.includes(title,)}onChange={filterCheckboxOnChange}/>)})}</CheckboxGroup></Box></DialogBody><DialogFooter><DialogActions><Button variant="primary" onClick={applyFilters}>Apply</Button><Button onClick={resetFilters}>Clear all filters</Button></DialogActions></DialogFooter></Dialog><Dialogaria-label="Employee information visible columns"{...columnsDialogProps}><DialogHeader>Columns</DialogHeader><DialogBody><CheckboxGroupname="columnsOptions"legend="Column options"visuallyHideLabel><Checkboxvalue="name"label="Name"checked={columnsCheckboxChecked.includes('name')}onChange={columnsCheckboxOnChange}/><Checkboxvalue="department"label="Department"checked={columnsCheckboxChecked.includes('department')}onChange={columnsCheckboxOnChange}/><Checkboxvalue="jobTitle"label="Job title"checked={columnsCheckboxChecked.includes('jobTitle')}onChange={columnsCheckboxOnChange}/><Checkboxvalue="emailAddress"label="Email address"checked={columnsCheckboxChecked.includes('emailAddress')}onChange={columnsCheckboxOnChange}/></CheckboxGroup></DialogBody><DialogFooter><DialogActions><Buttonvariant="primary"onClick={() => {columnsDialogProps.onClose()updateColumnVisibility()}}>Apply</Button><Button onClick={resetColumnsOptions}>Reset</Button></DialogActions></DialogFooter></Dialog></>}/><DataCardList aria-label="Employee information">{employees.map(employee => {return (<DataCardaria-label={employee['Name-FL']}key={`emp-${employee.Digit}`}selected={rowSelected[employee.Digit]}><DataCardCheckboxlabel={`Select ${employee['Name-FL']}`}checked={rowSelected[employee.Digit] || false}onChange={() => toggleSelected(employee.Digit)}/>{columnsDisplayed.includes('name') ? (<DataCardRecord heading="Name"><Link href="https://gusto.com/">{employee['Name-FL']}</Link></DataCardRecord>) : null}{columnsDisplayed.includes('department') ? (<DataCardRecord heading="Department"><Link href="https://gusto.com/">{employee.Department}</Link></DataCardRecord>) : null}{columnsDisplayed.includes('jobTitle') ? (<DataCardRecord heading="Job title"><Link href="https://gusto.com/">{employee.Title}</Link></DataCardRecord>) : null}{columnsDisplayed.includes('emailAddress') ? (<DataCardRecordheading={<Label htmlFor={emailId + String(employee.Digit)}>Email Address</Label>}><InputautoComplete="email"id={emailId + String(employee.Digit)}value={employee.Email}readOnly/></DataCardRecord>) : null}</DataCard>)})}</DataCardList><Box marginTop={4}><Pagination aria-label="Employee information list" variant="floating"><PaginationPerPageSelectField /><PaginationNavigation><PaginationNavigationButton variant="first" /><PaginationNavigationButton variant="previous" /><PaginationNavigationButton variant="next" /><PaginationNavigationButton variant="last" /></PaginationNavigation></Pagination></Box></Box></Box>)}
The following props are associated to the
ControlLayout
layout helper for the Control Layout patternName | Type | Default | Description |
---|---|---|---|
searchField | ReactNode | - | The search input for the data set; Can be a Autocomplete or TextField |
selectAllCheckbox | ReactNode | - | The select all checkbox for rows within the data set |
selectAllActionsMenu | ReactNode | - | The action menu associated to the "select all" rows checkbox |
actions | ReactNode | - | The actions that are associated with updating the data set such as filtering, visibility, etc. |