Skip to main content

· 2 min read
Anita

Breaking changes

  • csx prop no longer accepted by any component
  • Box, FilterBar, Collapsible, CollapsibleGroup and List components deprecated
  • Input object for useSwitchState changed format

Codemod

to use the codemod that removes Box component (and replaces it) and replaces csx prop run the command:

npx @vtex/admin-ui-codemod remove-csx ./

remember to lint after running the codemod, to maintain your linting specifications.

Switch

before

const props = useSwitchState({ state: { defaultValue: [] }})

return <Switch
state={props}
aria-label="label1"
label="label"
value="switch1"
/>

after

  • input for useSwitchState changed from { state: { ... }} to { ... }
const props = useSwitchState({ defaultValue: [] })

return <Switch
state={props}
aria-label="label1"
label="label"
value="switch1"
/>

Styling model review

The styling paradigm for all components has been changed. Components no longer accept the csx prop, they instead accept a className prop. You can use the csx function exported by admin-ui to generate classNames from style objects.

before


<Button csx={ marginRight: '$m' } />

after


<Button className={csx({ marginRight: '$m' })} />

Motivation for the change

  • Improve rendering performance for all components
  • Compatibility with any css library, as long as you use className

ATTENTION POINT 🚨

Some components utilize data attribute selectors to handle styling when there's multiple styling options for the same component. To change styles that are under a data attribute selector, you must use data selectors too. For more details check our documentation.


Box

Box has been deprecated and can be replaced by divs or other components with a className.

before


<Box csx={ marginRight: '$m' } />
<Box as="span" csx={ marginRight: '$m' } />

after


<div className={csx({ marginRight: '$m' })} />
<span className={csx({ marginRight: '$m' })} />

Fixes

  • Zindex overlap issues
  • Divider a11y (aria-direction)

Features

  • usePaginationState now accepts optional onNextPage and onPrevPage callbacks

· 4 min read
Anita

Csx multi-token resolve

You can now resolve multiple tokens at once. This is useful to compound properties like margin, padding, box-shadow, border, etc. For example:

const container = csx({
margin: '$space-10 $space-20',
padding: '$space-10',
border: '4px dotted $blue40',
})

Tokens

Space

Codemod: npx @vtex/admin-ui-codemod space-tokens-review ./

The current tokens are:

tokenvalue
space-00rem
space-050.125rem
space-10.25rem
space-20.5rem
space-30.75rem
space-41rem
space-51.25rem
space-61.5rem
space-71.75rem
space-82rem
space-102.5rem
space-123rem
space-164rem
space-205rem
space-246rem
space-287rem
space-328rem

Multi-token csx resolve

Border Radius

Codemod: npx @vtex/admin-ui-codemod radius-tokens-review ./

tokenvalue
none0
base0.25rem
pill100%

zIndices

Created tokens for elevation:

tokenvalue
z-10
z-2100
z-3200
z-4300
z-5400
z-6500
z-7600
z-8700
z-9800
z-10900

useCollapsible

Implemented the discussion: https://github.com/vtex/admin-ui/discussions/438#discussion-4527541.

Before

We use the collapsible component with a state hook.

import {
useCollapsibleState,
Collapsible,
CollapsibleHeader,
CollapsibleContent,
} from '@vtex/admin-ui'

function Example() {
const state = useCollapsibleState()

return (
<Collapsible state={state}>
<CollapsibleHeader label="your label" />
<CollapsibleContent> your content </CollapsibleContent>
</Collapsible>
)
}

After

Replace the collpasible with the useCollapsible hook, which returns the props (using the prop-getters pattern).

function Example() {
const { getToggleProps, getCollapseProps } = useCollapsible()

return (
<Card>
<CardHeader {...getToggleProps()}>
<CardTitle>Your title</CardTitle>
</CardHeader>
<CardContent {...getCollapseProps()}>Your content</CardContent>
</Card>
)
}

Abstracting

The developer can abstract the component into a stateful accordion, or whatever makes sense for the application.

// accordion.tsx
interface Props {
title: ReactNode
content: ReactNode
}

export function Accordion (props: Props) {
const { title, content } = props
const { getToggleProps, getCollapseProps } = useCollapsible()

return (
<Card>
<CardHeader {...getToggleProps()}>
<CardTitle>{title}</CardTitle>
</CardHeader>
<CardContent {...getCollapseProps()}>{content}</CardContent>
</Card>
)
}

// usage.tsx
import { Accordion } from './accordion.tsx'

<Accordion title="Your title" content="your content" />

The Modal component was reviewed to the latest design specs. The API also changed a composable and flexible approach, allowing users to take advantage of our components to create custom, but consistent, Modals.

Before

function ModalDialog() {
const modal = useModalState()

return (
<Box>
<ModalDisclosure state={modal}>
<Button>Publish</Button>
</ModalDisclosure>
<Modal aria-label="Publish modal" state={modal} size="small">
<ModalHeader title="Publish content" />
<ModalContent>
<Text>
Are you sure you want to publish this content? This action cannot be
undone.
</Text>
</ModalContent>
<ModalFooter>
<Button variant="secondary">Cancel</Button>
<Button>Confirm</Button>
</ModalFooter>
</Modal>
</Box>
)
}

After

  • ModalDisclosure is deprecated. You can use any button (or effect) to act as disclosure.
  • ModalHeader is composed of the new ModalTitle and ModalDismiss components.
function ModalDialog() {
const modal = useModalState()

return (
<Box>
<Button onClick={() => modal.open()}>Publish</Button>
<Modal aria-label="Publish modal" state={modal} size="small">
<ModalHeader>
<ModalTitle>Publish content</ModalTitle>
<ModalDismiss />
</ModalHeader>
<ModalContent>
<Text>
Are you sure you want to publish this content? This action cannot be
undone.
</Text>
</ModalContent>
<ModalFooter>
<ModalButton variant="secondary">Cancel</ModalButton>
<ModalButton>Confirm</ModalButton>
</ModalFooter>
</Modal>
</Box>
)
}

Now you are able to customize the Search placeholder when necessary by using the placeholder property.

<Search value={value} onChange={onChange} placeholder="Search for..." />

· 3 min read
Lucas

Components

Table

Improvements on the table render performance

Breaking Changes

  • Table composites are now required to implement the Table component
  • onRowClick is defined using the TBodyRow onClick property
  • useTableState doesn't receive the useDataView state return anymore, now it only receives the status
  • getRowKey doesn't exist anymore, since now the user has full control of the item

Before

import { Table, createColumns, useTableState } from '@vtex/admin-ui'

const columns = createColumns(...)
const items = [...]

function Example() {
const state = useTableState({
columns,
items,
})

return <Table state={state} />
}

After

import {
Table,
THead,
THeadCell,
TBody,
TBodyRow,
TBodyCell,
createColumns,
useTableState
} from '@vtex/admin-ui'

const columns = createColumns(...)
const items = [...]

function Example() {
const { getTable, getHeadCell, getBodyCell, data } = useTableState({
columns,
items,
})

return (
<Table {...getTable()}>
<THead>
{columns.map((column) => {
<THeadCell {...getHeadCell(column)} />
})
</THead>
<TBody>
{items.map((item) => (
<TBodyRow>
{columns.map((column) => (
<TBodyCell {...getBodyCell(column, item)} />
))}
</TBodyRow>
)}
</TBody>
</Table>
)
}

Text resolver improvement

Columns using the Text resolver with descriptions that are too long, it is possible to truncate it by setting the overflow prop.

Usage

const columns = createColumns([
{
id: 'productName',
header: 'Name',
resolver: {
type: 'text',
columnType: 'name',
overflow: 'ellipsis',
mapText: (item) => item.productName,
mapDescription: (item) => item.description,
},
},
// other columns
])

Fixes

  • Fixed columns are repositioned when the window is resized to prevent them from being in the wrong position.
  • Avoid menu popover from getting stuck on the table when the menu is active (Menu resolver).

Pagination component review

Breaking changes

  • Before, when setting the total of items in the pagination the page was reset to the first one. Now when setting the total of items the page remains the same. This change was made due to the many issue we've received regarding this behavior.

Skeleton

Improvements in the UI

DataView

New features

  • DataViewActions -> A container to help organize the actions on the Header

Breaking changes

  • DataViewControls was renamed to DataViewHeader
  • Now all the status messages are defined and translated internally.
  • not-found status doesn't have the option to add a suggestion anymore.

Before

import { DataView, DataViewControls, useDataViewState } from '@vtex/admin-ui'

function Example() {
const view = useDataViewState()

return (
<DataView state={view}>
<DataViewControls>
<Search id="search" placeholder="Search" state={search} />
<Flex>
<Button variant="neutralTertiary">Button 1</Button>
<Button variant="neutralTertiary">Button 2</Button>
<Button variant="neutralTertiary">Button 3</Button>
</Flex>
</DataViewControls>
{table}
</DataView>
)
}

After

Before

import {
DataView,
DataViewHeader,
DataViewActions,
useDataViewState,
} from '@vtex/admin-ui'

function Example() {
const view = useDataViewState()

return (
<DataView state={view}>
<DataViewHeader>
<Flex justify="space-between">
<Search id="search" placeholder="Search" state={search} />
<DataViewActions>
<Button variant="neutralTertiary">Button 1</Button>
<Button variant="neutralTertiary">Button 2</Button>
<Pagination />
</DataViewActions>
</Flex>
<FilterGroup>...</FilterGroup>
</DataViewHeader>
{table}
</DataView>
)
}

@vtex/admin-ui-form

  • export useFieldArray to improve the validation ste

    p

· 11 min read
Matheus

Core

Theme

Below you can check the new updates, but you should also check the documentation to understand the improvements. ​

  • Using the Admin UI theme just got easier. The createSystem function is not needed anymore, just import the ThemeProvider directly.
  • The way of styling a native JSX element was also simplified. Now, it is possible to import directly from admin-ui a function called csx to create a className with the styles. The csx function only uses the default theme under the hood.
  • The ThemeProvider provides a new prop called experimentalTheme for those cases when you need to override the default theme and meet some specific design requirements. The experimentalTheme prop will receive the new theme object.
  • The ThemeProvider provides a new boolean prop called experimentalDisabledGlobalStyles to disable all the default global styles and enable the use of your own global styles.
  • The colors and typography theme tokens are now parsed to CSS variables.

· 8 min read
Lenderson

Bug Fixes

  • Inline: margin styles were being applied not only to direct children but for all nested children
  • Combobox: empty state only appeared when 2 or more letters were entered, causing a confusing delay