Tile
Tiles are container components. Use them to group similar components or to wrap components which the user may reorder or resize.
To learn more about how to use Tiles refer to the Tile pattern documentation.
Example
<Tile> <div>Some example content</div> </Tile>
Usage Rules
Don’t:
- Nest tiles
Variants
Actions
Tile Actions provide controls in the context of the Tile's content. They may contain input components such as an IconButton or Input. Actions may have a size of $spacing-4
(32px).
To learn more about how to use Tile actions refer to the Tile pattern documentation.
function TileWithIconButtonsAsActions() { const [title, setTitle] = useState('Icon Buttons as actions'); return ( <Tile title={title} onTitleChange={setTitle} titlePlaceholder="Placeholder" actions={[ <IconButton key="edit" iconName="Edit" aria-label="Edit" />, <IconButton key="settings" iconName="CogWheel" aria-label="Settings" /> ]} > <div>Some example content</div> </Tile> ); }
function TileWithSearchFieldAsAction() { const [title, setTitle] = useState('Search field as action'); return ( <Tile title={title} onTitleChange={setTitle} titlePlaceholder="Placeholder" actions={[ <Input key="search" aria-label="Search" onChange={() => {}} type="search" /> ]} > <div>Some example content</div> </Tile> ); }
Clickable
You can add onClick
to handle the click event.
function myTile() { const handleClick = () => { alert('Tile Clicked!'); }; return ( <Tile onClick={handleClick}> <div>Some example content</div> </Tile> ); }
Contentless
You can use the Tile without content without providing the child element.
function myTile() { const handleClick = () => { alert('Tile Clicked!'); }; return ( <Tile title="Adjust" /> ); }
If ESLint's react/jsx-key
rule is active make sure to set a key on the individual action components!
Disabled
The Tile can be disabled by adding prop disabled
to the component.
function myTile() { const handleClick = () => { alert('Tile Clicked!'); }; return ( <Tile onClick={handleClick} disabled> <div>Some example content</div> </Tile> ); }
Draggable
The Tile comes with properties that set styles to indicate whether a Tile is draggable or currently being dragged.
It also supports react-grid-layout for dragging functionality. See an example here.
<> <Tile draggable> <div>draggable</div> </Tile> <Tile draggable dragging> <div>dragging</div> </Tile> </>
Full Height
You can set the height of Tile to be 100% of container element by adding prop fullHeight
.
<div style={{ height: '250px'}}> <Tile title='Full Height Tile' titlePlaceholder="Placeholder" description="This is a description with rich text, such as <i>italic</i>, <strong>bold</strong>, or <a href='#'>links</a>." actions={[ <IconButton key="edit" iconName="Edit" aria-label="Edit" />, <IconButton key="settings" iconName="CogWheel" aria-label="Settings" /> ]} fullHeight > <div style={{ overflow: 'scroll', height: '100%'}}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. <br/><br/> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. </div> </Tile> </div>
Icons & App Icons
You can add icons to Tile by passing iconName
.
<div> <Tile title="User details" iconName="Person" css={{ marginBottom: '16px' }}> <div>Some example content</div> </Tile> </div>
You can also add app icons with appIcon
(ReactNode) as an external component (mfe-components). Recommended size is small
.
import { AppIcon } from '@adjust/mfe-components ';
<Tile title="Adjust" appIcon={<AppIcon appId="com.adjust.insights" appName="adjust Insights" size="small" />}>
<div>Some example content</div>
</Tile>
Icon customization
- You can custom Icon by using
customIcon
prop with React Element. Icon can be customised with Icons component or external svg component. - Using
iconPosition
to set icon position such asleft
orright
. - Using
customIconSize
to set the width and height of icon such as32
,64
, ... with24
(medium icon size) is default size.
function MyTile() { const IconSGV = () => ( <svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg" > <path fill-rule="evenodd" clip-rule="evenodd" d="M14.4547 1.48752C20.0554 0.496491 25.9038 0.000976562 32 0.000976562C38.0962 0.000976562 43.9446 0.496491 49.5453 1.48752L49.5453 1.48739C56.1625 2.65795 61.343 7.83852 62.5136 14.4557C63.5045 20.0564 64 25.9048 64 32.001C64 38.0972 63.5045 43.9456 62.5135 49.5463L62.5136 49.5463C61.343 56.1634 56.1625 61.344 49.5453 62.5146C43.9446 63.5055 38.0962 64.001 32 64.001C25.9038 64.001 20.0554 63.5055 14.4547 62.5144L14.4547 62.5146C7.83755 61.344 2.65698 56.1634 1.48641 49.5463C0.495514 43.9456 0 38.0972 0 32.001C0 25.9048 0.495514 20.0564 1.48654 14.4557L1.48641 14.4557C2.65698 7.83852 7.83755 2.65795 14.4547 1.48739L14.4547 1.48752Z" fill="#F9E6FF" /> <path d="M29.5988 30.501C34.4589 30.501 38.3988 26.5835 38.3988 21.751C38.3988 16.9185 34.4589 13.001 29.5988 13.001C24.7387 13.001 20.7988 16.9185 20.7988 21.751C20.7988 26.5835 24.7387 30.501 29.5988 30.501Z" fill="#C87AFE" /> <path d="M31.074 32.7322C30.59 32.7104 30.106 32.6885 29.6 32.6885C24.276 32.6885 19.304 34.1541 15.058 36.6697C13.122 37.8072 12 39.951 12 42.2041V48.001H32.372C30.634 45.5291 29.6 42.5104 29.6 39.251C29.6 36.9104 30.15 34.7229 31.074 32.7322Z" fill="#C87AFE" /> <path d="M43 31.801V27.001L36.75 33.001L43 39.001V34.201C47.1375 34.201 50.5 37.429 50.5 41.401C50.5 45.373 47.1375 48.601 43 48.601C38.8625 48.601 35.5 45.373 35.5 41.401H33C33 46.705 37.475 51.001 43 51.001C48.525 51.001 53 46.705 53 41.401C53 36.097 48.525 31.801 43 31.801Z" fill="#C87AFE" /> </svg> ); return ( <div> <Tile title="Custom SVG Icon" description="This is a description with rich text, such as <i>italic</i>, <strong>bold</strong>, or <a href='#'>links</a>." customIcon={<IconSGV />} customIconSize={64} > <div>Some example content</div> </Tile> <Tile title="Custom icon on the right side" iconPosition="right" customIcon={ <Tooltip content="Tooltip"> <Icon name="WarningFilled" /> </Tooltip> } css={{ marginTop: '16px' }} > <div>Some example content</div> </Tile> </div> ); }
ShowOverflow
The Tile component's overflow
is set to 'hidden' by default but if there is a case you need it to be visible you can use showOverflow
prop to achieve it.
function MyTile() { const [visibility, setVisibility] = useState(false); const showInfoMessage = () => { setVisibility(!visibility); }; return ( <div> <Tile css={{ width: 200, marginRight: 'auto' }} showOverflow> <Button label="Toggle message" onClick={showInfoMessage} /> {visibility && ( <Banner title="Warning" description="Some more information" kind="warning" css={{ position: 'absolute', right: -250, top: 0 }} /> )} </Tile> </div> ); }
Resizable
The Tile comes with properties that set styles to indicate whether a Tile is resizable or currently being resized.
It also supports react-grid-layout for resizing functionality. See an example here.
<> <Tile resizable> <div>resizable</div> </Tile> <Tile resizable resizing> <div>resizing</div> </Tile> </>
Title & Optional Badge & CTA Button
title
anddescription
are optional props to display the title and description in Tile Header.description
also suppoprts rich text tag such as<b>
,<i>
,<a>
and<strong>
.titleBadge
is an optional prop to show a badge beside the Title.actions
prop can provide the CTA button on the right side. Please use only the Atlas Button component with the default Button kind and size.
<Tile title="Title" titleBadge="Optional" description="Subtitle" actions={[ <Button iconName="Edit" iconAlignment="left" label="Edit" /> ]} > <div>Some example content</div> </Tile>
Title & Description
title
anddescription
are optional props to display the title and description in Tile Header.description
also suppoprts rich text tag such as<b>
,<i>
,<a>
and<strong>
.
<Tile title="My title" description="This is a description with rich text, this is a description with rich text, this is a description with rich text, this is a description with rich text, such as <i>italic</i>, <strong>bold</strong>, or <a href='#'>links</a>." actions={[ <IconButton key="edit" iconName="Edit" aria-label="Edit" />, <IconButton key="settings" iconName="CogWheel" aria-label="Settings" /> ]} > <div>Some example content</div> </Tile>
You can provide onTitleChange
prop to make the title editable.
function TileWithEditableTitle() { const [title, setTitle] = useState('Editable title'); return ( <Tile title={title} onTitleChange={setTitle} titlePlaceholder="Placeholder"> <div>Some example content</div> </Tile> ); }
Titles could also be represented with ReactNode
.
ReactNode
passed to <Tile>
will be rendered within a component that sets title font styles to ensure consistent text display.
function TileWithReactNodeTitle() { const Title = () => ( <> Title with a <Tooltip content='Tooltips can provide more info for particular title parts'> <span>tooltip</span> </Tooltip> </> ); return ( <Tile title={<Title />}> <div>Some example content</div> </Tile> ); }
You can set titleRequired
to true
to disallow the use of an empty string as the title value.
function TileWithRequiredTitle() { const [title, setTitle] = useState('Title is required'); return ( <Tile title={title} titleRequired onTitleChange={setTitle} titlePlaceholder="Placeholder" > <div>Some example content</div> </Tile> ); }
Sidebar
The Tile also supports a Sidebar by using props:
sidebar.content
sidebar.isOpen
sidebar.onClosed
sidebar.closeButtonLabel
sidebar.secondaryButtonLabel
,sidebar.onSecondaryClick
,sidebar.sidebarWidth
,sidebar.justifyContent
sidebar.noPreviewMessage
: tile's body will not be previewed if small screen (< 240px)
function TileWithSidebar() { const [isSidebarOpen, setIsSidebarOpen] = useState(false); const [title, setTitle] = useState('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere.'); return ( <Tile title={title} actions={[ <IconButton key="dots" iconName="DotsHorizontal" onClick={() => setIsSidebarOpen(true)} /> ]} iconName="Warning" iconPosition="left" sidebar={{ content: ( <div> <b>Lorem ipsum</b> <br /> <br /> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. </div> ), isOpen: isSidebarOpen, onClosed: () => setIsSidebarOpen(false), closeButtonLabel: 'Close', secondaryButtonLabel: 'Clear', onSecondaryClick: () => {}, sidebarWidth: 400, justifyContent: 'end', noPreviewMessage: 'No Preview Available' }} > <div> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. <br/> <br/> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in aliquet dolor, sed placerat sem. Nunc lobortis arcu vitae pellentesque posuere. </div> </Tile> ); }
Examples
Drag-and-drop and resizing Tiles using react-grid-layout
The following example shows how to set up drag-and-drop and resizing of the Tile using react-grid-layout.
Note that additional global styling is required to enable the same UX as you can find in the design specifications. Especially, for the drag and resizing placeholder (see here).
// import GridLayout, { WidthProvider } from 'react-grid-layout'; function MyGrid() { const Grid = WidthProvider(GridLayout); const layout = [ { i: 'a', x: 0, y: 0, w: 1, h: 2, minH: 2 }, { i: 'b', x: 1, y: 0, w: 2, h: 2, minH: 2 }, { i: 'c', x: 3, y: 0, w: 1, h: 2, minH: 2 } ]; return ( <Grid layout={layout} cols={4} rowHeight={30} /* This className is predefined in the Tile component! */ draggableHandle=".draggableHandle" onDragStart={console.log} onDragStop={console.log} > <Tile draggable resizable key="a"> A </Tile> <Tile draggable resizable key="b"> B </Tile> <Tile draggable resizable key="c"> C </Tile> </Grid> ); }
Tile with a scrolling Panel inside
<Tile title={'Tile with a panel inside'} padding="none" titlePlaceholder="Placeholder" actions={[ <Input key="search" aria-label="Search" onChange={() => {}} type="search" /> ]} > <Panel title="Panel inside a Tile" borders={[true, false, false, false]} padding="standard" css={{ height: 300 }} > <div style={{ height: 400, padding: 200 }}>Scrollable content</div> </Panel> </Tile>
Tile with Scrollable Table
function MyTable() { const generateMoreData = useCallback( (offset = 0, chunkSize = 25) => Array.from({ length: chunkSize }, (_, index) => { const id = offset + index + 1; return { firstName: `firstName_${id}`, lastName: `lastName_${id}`, points: id }; }), [] ); const initialData = useMemo(() => generateMoreData(), [generateMoreData]); const [data, setData] = useState(initialData); const dataLength = data.length; const [isLoadingMoreData, setIsLoadingMoreData] = useState(false); const columns = useMemo( () => [ { Header: 'First Name', accessor: 'firstName' }, { Header: 'Last Name', accessor: 'lastName', width: 300, Cell: ({ value }) => <Badge label={value} /> }, { Header: 'Points', accessor: 'points', align: 'right' } ], [] ); const onLoadMoreData = useCallback(() => { setIsLoadingMoreData(true); setTimeout(() => { const generatedData = generateMoreData(dataLength); setData((initialData) => [...initialData, ...generatedData]); setIsLoadingMoreData(false); }, 3000); }, [dataLength, generateMoreData]); const maxNumberOrRows = 200; return ( <div style={{ height: '500px'}}> <Tile title='Scrollable Table' titlePlaceholder="Placeholder" description="This is a description with rich text, such as <i>italic</i>, <strong>bold</strong>, or <a href='#'>links</a>." actions={[ <IconButton key="edit" iconName="Edit" aria-label="Edit" />, <IconButton key="settings" iconName="CogWheel" aria-label="Settings" /> ]} fullHeight > <TableV2 data={data} columns={columns} hasMoreData={dataLength <= maxNumberOrRows} isLoadingMoreData={isLoadingMoreData} onLoadMoreData={onLoadMoreData} height='100%' /> </Tile> </div> ); }
Props
Name | Type | Default |
---|---|---|
title The title of the Tile |
| — |
description The description of the Tile |
| — |
iconPosition The icon position (left or right of title) |
| "left" |
appIcon The external app icon (mfe-shared-context) |
| — |
iconName Name of the Icon that would appear next to the title. Please refer to the full list of icons here: Link | "AddValue" | "Adjust" | "AIAgent" | "AppGrid" | "ArrowCircleLeft" | "ArrowCircleRight" | "ArrowDown"... | — |
customIcon The icon that would appear next to the title |
| — |
customIconSize The size of custom Icon, eg: 32 (32x32), 64 (64x64) |
| 24 |
titlePlaceholder Placeholder for the title. Used only for editable title |
| — |
titleRequired Can be set to true to disallow the use of an empty string as the title value. |
| false |
titleBadge A badge content for the title |
| — |
onTitleChange Callback on the title change. Can be provided to make the title editable |
| — |
actions A list of tile actions. |
| [] |
padding This will define padding in the body of the Tile. |
| — |
showOverflow This will make the overflow visible |
| — |
draggable This will activate a styling indicating that the tile is draggable |
| — |
dragging This will activate a styling indicating that the tile is currently being dragged. It only works if draggable is set. |
| — |
resizable This will activate a styling indicating that the tile is resizable |
| — |
resizing This will activate a styling indicating that the tile is currently being resized. It only works if resizable is set. |
| — |
children The content of the tile |
| — |
onClick onClick function to handle clicks |
| — |
sidebar The sidebar displayed within the tile | { content: ReactNode; isOpen: boolean; onClosed: () => void; closeButtonLabel?: string; sidebarWidth... | — |
disabled Allow to disable tile |
| — |
fullHeight Allow to display tile with 100% height of container |
| — |
css Add custom styles to this component. Use with caution. Learn more here: Link |
| — |
inputFieldCss |
| — |
data-{foo} Data attributes can be used by testing libraries to retrieve components or assert their existence |
| — |
* - the prop is required. |