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.