Skip to main content

Layout

The layout component included three main parts: Header, Content, and Footer. You can design your Layout with the child layout components as in the following examples.

Example

Live Editor
function MyLayout() {
  const breadcrumbsData = [
    { label: 'Deliverables', url: '/deliverables' },
    { label: 'NetworkD', url: '/networkd' },
    { label: 'Creative_H' }
  ];

  const titleConfig = {
    text: 'Page Title',
    isEditable: true
  };

  const actions = {
    iconActions: [
      {
        id: 'fav',
        name: 'Star',
        tooltip: {
          content: 'Rate us'
        },
        onClick: () => console.log('fav is clicked')
      },
      {
        id: 'settings',
        name: 'CogWheel',
        tooltip: {
          content: 'App settings'
        },
        onClick: () => console.log('settings is clicked')
      },
      {
        id: 'share',
        name: 'Share',
        tooltip: {
          content: 'Share with your connection'
        },
        onClick: () => console.log('share is clicked')
      },

      {
        id: 'download',
        name: 'Download',
        tooltip: {
          content: 'Download report'
        },
        onClick: () => console.log('download is clicked')
      }
    ],
    buttonActions: {
      primaryAction: {
        label: 'Primary',
        isLoading: true,
        disabled: true,
        tooltip: {
          content: 'Please wait...'
        },
        onClick: () => console.log('primary action clicked')
      },
      secondaryAction: {
        label: 'Secondary',
        onClick: () => console.log('secondary action clicked')
      }
    }
  };

  const tabs = [
    { id: '1', label: 'Examples', url: '#' },
    {
      id: '2',
      label: 'Components',
      url: 'https://atlas.adjust.com/docs/components/introduction'
    },
    {
      id: '3',
      label: 'Design Tokens',
      url: 'https://atlas.adjust.com/docs/design-tokens/introduction'
    },
    {
      id: '4',
      label: 'Patterns',
      url: 'https://atlas.adjust.com/docs/patterns/introduction'
    }
  ];

  const getSearchValue = (event) => {
    const searchValue = event.target.value;
    return console.log('search value:', searchValue);
  };

  const search = {
    onChange: getSearchValue,
    placeholder: 'Search...'
  };

  const FilterComponents = () => {
    const items = [
      {
        label: 'apple',
        value: 'apple'
      },
      {
        label: 'banana',
        value: 'banana'
      }
    ];

    const [selectedItems, setSelectedItems] = useState(items);

    return (
      <>
        <FilterButton
          name="Fruits"
          items={items}
          selectedItems={selectedItems}
          onApply={setSelectedItems}
          showResetButton
        />
        <FilterButton
          name="Fruits"
          items={items}
          selectedItems={selectedItems}
          onApply={setSelectedItems}
          showResetButton
        />
      </>
    );
  };

  const onTitleEdit = (updatedTitleValue) => {
    return console.log('edited title value', updatedTitleValue);
  };

  const footeractions = {
    primaryAction: {
      onClick: () => console.log('primaryAction clicked'),
      label: 'Save',
      isLoading: true,
      disabled: true,
      tooltip: {
        content: 'Saving please wait...'
      },
      dataTestId: 'primary-btn'
    },
    secondaryAction: {
      onClick: () => console.log('secondaryAction clicked'),
      label: 'Reset',
      dataTestId: 'secondary-btn'
    },
    destructiveAction: {
      onClick: () => console.log('destructiveAction clicked'),
      label: 'Delete',
      dataTestId: 'destructive-btn',
      disabled: true,
      tooltip: {
        content: 'Delete action is disabled'
      }
    }
  };

  const columns = [
    {
      Header: 'Name',
      accessor: 'name'
    },
    {
      Header: 'Age',
      accessor: 'age',
      align: 'center'
    },
    {
      Header: 'Room',
      accessor: 'room',
      align: 'right'
    }
  ];
  const data = [
    {
      name: 'Just a name',
      age: 21,
      room: 1
    },
    {
      name: 'Another name',
      age: 25,
      room: 2
    }
  ];

  return (
    <Layout>
      <Layout.Header>
        <PageHeader
          breadcrumbs={breadcrumbsData}
          title={titleConfig}
          actions={actions}
          onTitleEdit={onTitleEdit}
          tabs={tabs}
          search={search}
          filters={<FilterComponents />}
          css={{ position: 'sticky', zIndex: 100 }} // to fit with Preview Container. To see header fixed to top of the page, change position: 'fixed', zIndex: 200
        />
      </Layout.Header>
      <Layout.Content>
        <Tile>
          <Text type="headline1">List</Text>
          <TableV2 data={data} columns={columns} />
        </Tile>
      </Layout.Content>
      <Layout.Footer>
        <PageFooter
          primaryAction={footeractions.primaryAction}
          secondaryAction={footeractions.secondaryAction}
          destructiveAction={footeractions.destructiveAction}
          contextMessage="This is a contextual message."
          isFluidWidth
          css={{ position: 'relative' }} // to fit with Preview Container.
        />
      </Layout.Footer>
    </Layout>
  );
}
Result
Loading...

Components

The <Layout.Header /> component is responsible for keeping your page header in the layout grid.

info

Please use the PageHeader component for the header part.

Live Editor
<Layout noFooter>
  <Layout.Header>
    <PageHeader
      title={{ text: 'Header Title' }}
      kind="wizard"
      css={{ position: 'sticky', zIndex: 100 }} // to fit with Preview Container. To see header fixed to top of the page, change position: 'fixed', zIndex: 200
    />
  </Layout.Header>
  <Layout.Content noPadding>...</Layout.Content>
</Layout>
Result
Loading...

Content

The <Layout.Content /> component is responsible for keeping your page content in the layout grid. It has two options:

noPadding: In case you don't want to use default padding in your content area, you can provide the prop noPadding to the <Layout.Content /> component as in the following example.

Live Editor
<Layout noFooter>
  <Layout.Header>
    <PageHeader
      title={{ text: 'Header Title' }}
      kind="wizard"
      css={{ position: 'sticky', zIndex: 100 }} // to fit with Preview Container. To see header fixed to top of the page, change position: 'fixed', zIndex: 200
    />
  </Layout.Header>
  <Layout.Content noPadding>
    <span>Content without padding</span>
  </Layout.Content>
</Layout>
Result
Loading...

onContentScroll: you can use this callback prop to get information about the scroll value inside <Layout.Content /> component.

Live Editor
function MyLayout() {
  const primaryAction = {
    onClick: () => console.log('primaryAction clicked'),
    label: 'Save',
    isLoading: true,
    disabled: true,
    tooltip: {
      content: 'Saving please wait...'
    },
    dataTestId: 'primary-btn'
  };

  const handleScroll = (scrollValue) => {
    return console.log(scrollValue);
  };

  return (
    <Layout>
      <Layout.Header>
        <PageHeader
          title={{ text: 'Header Title' }}
          kind="wizard"
          css={{ position: 'sticky', zIndex: 100 }} // to fit with Preview Container. To see header fixed to top of the page, change position: 'fixed', zIndex: 200
        />
      </Layout.Header>
      <Layout.Content onContentScroll={handleScroll}>
        <div>
          <Tile>
            <div>Some example content</div>
          </Tile>
          <Tile>
            <div>Some example content</div>
          </Tile>
          <Tile>
            <div>Some example content</div>
          </Tile>
          <Tile>
            <div style={{height: '500px'}}>Some example content</div>
          </Tile>
          <Tile>
            <div>Some example content</div>
          </Tile>
          <Tile>
            <div>Some example content</div>
          </Tile>
        </div>
      </Layout.Content>
      <Layout.Footer>
        <PageFooter
          primaryAction={primaryAction}
          contextMessage="This is a contextual message."
          css={{ position: 'relative' }} // to fit with Preview Container.
        />
      </Layout.Footer>
    </Layout>
  );
}
Result
Loading...

The <Layout.Footer /> component is responsible for keeping your page footer in the layout grid. You also can exclude the footer from your layout by adding the prop noFooter prop to the <Layout /> component.

info

Please use the PageFooter component for the footer part.

Live Editor
function MyLayout() {
  const primaryAction = {
    onClick: () => console.log('primaryAction clicked'),
    label: 'Save',
    isLoading: true,
    disabled: true,
    tooltip: {
      content: 'Saving please wait...'
    },
    dataTestId: 'primary-btn'
  };

  const handleScroll = (scrollValue) => {
    return console.log(scrollValue);
  };

  return (
    <Layout>
      <Layout.Header>
        <PageHeader
          title={{ text: 'Header Title' }}
          css={{ position: 'sticky', zIndex: 100 }} // to fit with Preview Container. To see header fixed to top of the page, change position: 'fixed', zIndex: 200
        />
      </Layout.Header>
      <Layout.Content onContentScroll={handleScroll}>
        ...
      </Layout.Content>
      <Layout.Footer>
        <PageFooter
          primaryAction={primaryAction}
          contextMessage="This is a contextual message."
          css={{ position: 'relative' }} // to fit with Preview Container.
        />
      </Layout.Footer>
    </Layout>
  );
}
Result
Loading...

Variants

You can exclude the <Layout.Footer /> component from your composition by adding the prop noFooter to the <Layout /> component.

Live Editor
<Layout noFooter>
  <Layout.Header>
    <PageHeader
      title={{ text: 'Header Title' }}
      css={{ position: 'sticky', zIndex: 100 }} // to fit with Preview Container. To see header fixed to top of the page, change position: 'fixed', zIndex: 200
    />
  </Layout.Header>
  <Layout.Content>
    <div style={{ display: 'flex', justifyContent: 'center', height: '100%' }}>
      <EmptyState
        background="table"
        iconKey="warningOverload"
        size="large"
        headLine="Connection has been lost"
        bodyText="Data could not be loaded, or connection is missing."
      />
    </div>
  </Layout.Content>
</Layout>
Result
Loading...

Spinner

You can use the <Layout.Spinner /> component to show Spinner component while your layout is loading some pages or content. Spinner is a part of the content, please be sure that you are wrapping <Layout.Spinner /> component inside the <Layout.Content /> component as in the following example.

Live Editor
<Layout noFooter>
  <Layout.Header>
    <PageHeader
      title={{ text: 'Header Title' }}
      css={{ position: 'sticky', zIndex: 100 }} // to fit with Preview Container. To see header fixed to top of the page, change position: 'fixed', zIndex: 200
    />
  </Layout.Header>
  <Layout.Content>
    <Layout.Spinner size="medium" />
  </Layout.Content>
</Layout>
Result
Loading...

Wizard

You can use the layout as a wizard layout by adding the boolean prop wizard to the <Layout /> component. In case of using a wizard layout, please be sure that you are providing the prop kind="wizard" to the <PageHeader /> component as well.

Live Editor
function MyLayout() {
  const footeractions = {
    primaryAction: {
      onClick: () => console.log('primaryAction clicked'),
      label: 'Save',
      isLoading: true,
      disabled: true,
      tooltip: {
        content: 'Saving please wait...'
      },
      dataTestId: 'primary-btn'
    },
    secondaryAction: {
      onClick: () => console.log('secondaryAction clicked'),
      label: 'Reset',
      dataTestId: 'secondary-btn'
    },
    destructiveAction: {
      onClick: () => console.log('destructiveAction clicked'),
      label: 'Delete',
      dataTestId: 'destructive-btn',
      disabled: true,
      tooltip: {
        content: 'Delete action is disabled'
      }
    }
  };
  return (
    <Layout wizard>
      <Layout.Header>
        <PageHeader
          title={{ text: 'Header Title' }}
          kind="wizard"
          css={{ position: 'sticky', zIndex: 100 }} // to fit with Preview Container. To see header fixed to top of the page, change position: 'fixed', zIndex: 200
        />
      </Layout.Header>
      <Layout.Content>
        <EmptyState
          background="table"
          iconKey="warningOverload"
          size="large"
          headLine="Connection has been lost"
          bodyText="Data could not be loaded, or connection is missing."
        />
      </Layout.Content>
      <Layout.Footer>
        <PageFooter
          primaryAction={footeractions.primaryAction}
          secondaryAction={footeractions.secondaryAction}
          destructiveAction={footeractions.destructiveAction}
          contextMessage="This is a contextual message."
          isFluidWidth
          css={{ position: 'relative' }} // to fit with Preview Container.
        />
      </Layout.Footer>
    </Layout>
  );
}
Result
Loading...

Props

NameTypeDefault
noFooter
The appName will be used to inform layout to not use footer area in grid
boolean
wizard
The wizard will be used to inform layout to use wizard template layout
boolean
children
The sub layout components
ReactNode
data-{foo}
Data attributes can be used by testing libraries to retrieve components or assert their existence
string
* - the prop is required.