Skip to main content

Tile

Tiles are container components. Use them to group similar components or to wrap components which the user may reorder or resize.

tip

To learn more about how to use Tiles refer to the Tile pattern documentation.

Example

Live Editor
<Tile>
  <div>Some example content</div>
</Tile>
Result
Loading...

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.

Live Editor
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>
  );
}
Result
Loading...
Live Editor
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>
  );
}
Result
Loading...

Clickable

You can add onClick to handle the click event.

Live Editor
function myTile() {
  const handleClick = () => {
    alert('Tile Clicked!');
  };
  return (
    <Tile onClick={handleClick}>
      <div>Some example content</div>
    </Tile>
  );
}
Result
Loading...

Contentless

You can use the Tile without content without providing the child element.

Live Editor
function myTile() {
  const handleClick = () => {
    alert('Tile Clicked!');
  };
  return (
    <Tile title="Adjust" />
  );
}
Result
Loading...
note

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.

Live Editor
function myTile() {
  const handleClick = () => {
    alert('Tile Clicked!');
  };
  return (
    <Tile onClick={handleClick} disabled>
      <div>Some example content</div>
    </Tile>
  );
}
Result
Loading...

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.

Live Editor
<>
  <Tile draggable>
    <div>draggable</div>
  </Tile>
  <Tile draggable dragging>
    <div>dragging</div>
  </Tile>
</>
Result
Loading...

Full Height

You can set the height of Tile to be 100% of container element by adding prop fullHeight.

Live Editor
<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>
Result
Loading...

Icons & App Icons

You can add icons to Tile by passing iconName.

Live Editor
<div>
  <Tile title="User details" iconName="Person" css={{ marginBottom: '16px' }}>
    <div>Some example content</div>
  </Tile>
</div>
Result
Loading...

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 as left or right.
  • Using customIconSize to set the width and height of icon such as 32, 64, ... with 24 (medium icon size) is default size.
Live Editor
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>
  );
}
Result
Loading...

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.

Live Editor
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>
  );
}
Result
Loading...

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.

Live Editor
<>
  <Tile resizable>
    <div>resizable</div>
  </Tile>
  <Tile resizable resizing>
    <div>resizing</div>
  </Tile>
</>
Result
Loading...

Title & Optional Badge & CTA Button

  • title and description 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.
Live Editor
<Tile
  title="Title"
  titleBadge="Optional"
  description="Subtitle"
  actions={[
    <Button iconName="Edit" iconAlignment="left" label="Edit" />
  ]}
>
  <div>Some example content</div>
</Tile>
Result
Loading...

Title & Description

  • title and description 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>.
Live Editor
<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>
Result
Loading...

You can provide onTitleChange prop to make the title editable.

Live Editor
function TileWithEditableTitle() {
  const [title, setTitle] = useState('Editable title');

  return (
    <Tile title={title} onTitleChange={setTitle} titlePlaceholder="Placeholder">
      <div>Some example content</div>
    </Tile>
  );
}
Result
Loading...

Titles could also be represented with ReactNode.

note

ReactNode passed to <Tile> will be rendered within a component that sets title font styles to ensure consistent text display.

Live Editor
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>
  );
}
Result
Loading...

You can set titleRequired to true to disallow the use of an empty string as the title value.

Live Editor
function TileWithRequiredTitle() {
  const [title, setTitle] = useState('Title is required');

  return (
    <Tile
      title={title}
      titleRequired
      onTitleChange={setTitle}
      titlePlaceholder="Placeholder"
    >
      <div>Some example content</div>
    </Tile>
  );
}
Result
Loading...

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)
Live Editor
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>
  );
}
Result
Loading...

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).

Live Editor
// 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>
  );
}
Result
Loading...

Tile with a scrolling Panel inside

Live Editor
<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>
Result
Loading...

Tile with Scrollable Table

Live Editor
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>
  );
}
Result
Loading...

Props

NameTypeDefault
title
The title of the Tile
ReactNode
description
The description of the Tile
string
iconPosition
The icon position (left or right of title)
"left" | "right"
"left"
appIcon
The external app icon (mfe-shared-context)
ReactNode
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
ReactElement
customIconSize
The size of custom Icon, eg: 32 (32x32), 64 (64x64)
number
24
titlePlaceholder
Placeholder for the title. Used only for editable title
string
titleRequired
Can be set to true to disallow the use of an empty string as the title value.
boolean
false
titleBadge
A badge content for the title
string
onTitleChange
Callback on the title change. Can be provided to make the title editable
((text: string) => void)
actions
A list of tile actions.
ReactElement[]
[]
padding
This will define padding in the body of the Tile.
"small" | "default" | "none"
showOverflow
This will make the overflow visible
boolean
draggable
This will activate a styling indicating that the tile is draggable
boolean
dragging
This will activate a styling indicating that the tile is currently being dragged. It only works if draggable is set.
boolean
resizable
This will activate a styling indicating that the tile is resizable
boolean
resizing
This will activate a styling indicating that the tile is currently being resized. It only works if resizable is set.
boolean
children
The content of the tile
ReactNode
onClick
onClick function to handle clicks
(() => void)
sidebar
The sidebar displayed within the tile
{ content: ReactNode; isOpen: boolean; onClosed: () => void; closeButtonLabel?: string; sidebarWidth...
disabled
Allow to disable tile
boolean
fullHeight
Allow to display tile with 100% height of container
boolean
css
Add custom styles to this component. Use with caution. Learn more here: Link
SupportedStyleAttributes
inputFieldCss
SupportedStyleAttributes
data-{foo}
Data attributes can be used by testing libraries to retrieve components or assert their existence
string
* - the prop is required.