Layout

The Layout component is the basis of every single page view.

Introduction

The Layout component defines the page view by providing four distinct areas: Header, Body, Left Sidebar, and Right Sidebar. Use it at the top level of your page to create a clear and flexible structure. For best results, avoid placing the Layout inside modals or nesting multiple Layout components within each other.

Layout Compound components

Compound ComponentDescriptionTypical Usage Area
Layout.HeaderShould contain a Header component. When passing at least one sidebar, a divider is added underneath the header. Content inside will be centered. It follows through in the max-width adjustment from 1550px to 1920px on the wide variant.header
Layout.SidebarAllows for variants narrow (sets width: 280px) and wide (default, sets width: 340px). Both sidebars can have different widths.leftSidebar, rightSidebar
Layout.BodyWrapper around all children, this compound component is essential for proper overflow and scrolling behaviours.wrapper around all children of Layout

Import

import { Layout } from '@contentful/f36-components';
// or
import { Layout } from '@contentful/f36-layout';

Examples

Basic Layout with body only

function BasicLayoutExample() {
const [submitting, setSubmitting] = useState(false);
const submitForm = () => {
setSubmitting(true);
setTimeout(() => setSubmitting(false), 1000);
};
return (
<Layout>
<Layout.Body>
<Box padding="none" marginBottom="spacingXl">
<Form onSubmit={submitForm}>
<FormControl>
<FormControl.Label isRequired>Name</FormControl.Label>
<TextInput />
<FormControl.HelpText>
Please enter your first name
</FormControl.HelpText>
</FormControl>
<FormControl>
<FormControl.Label>Description</FormControl.Label>
<Textarea />
<FormControl.HelpText>
Tell me about yourself
</FormControl.HelpText>
</FormControl>
<Button variant="primary" type="submit" isDisabled={submitting}>
{submitting ? 'Submitted' : 'Click me to submit'}
</Button>
</Form>
</Box>
</Layout.Body>
</Layout>
);
}

Layout with header

function BasicLayoutExample() {
const [submitting, setSubmitting] = useState(false);
const submitForm = () => {
setSubmitting(true);
setTimeout(() => setSubmitting(false), 1000);
};
return (
<Layout
header={
<Layout.Header>
<Header title="Your Details" />
</Layout.Header>
}
>
<Layout.Body>
<Box padding="none" marginBottom="spacingXl">
<Form onSubmit={submitForm}>
<FormControl>
<FormControl.Label isRequired>Name</FormControl.Label>
<TextInput />
<FormControl.HelpText>
Please enter your first name
</FormControl.HelpText>
</FormControl>
<FormControl>
<FormControl.Label>Description</FormControl.Label>
<Textarea />
<FormControl.HelpText>
Tell me about yourself
</FormControl.HelpText>
</FormControl>
<Button variant="primary" type="submit" isDisabled={submitting}>
{submitting ? 'Submitted' : 'Click me to submit'}
</Button>
</Form>
</Box>
</Layout.Body>
</Layout>
);
}

Layout with left sidebar

function BasicLayoutExample() {
const [submitting, setSubmitting] = useState(false);
const submitForm = () => {
setSubmitting(true);
setTimeout(() => setSubmitting(false), 1000);
};
return (
<Layout
leftSidebar={
<Layout.Sidebar>
<Box padding="none" marginBottom="spacingXl">
<Paragraph>Sidebar Content</Paragraph>
</Box>
</Layout.Sidebar>
}
>
<Layout.Body>
<Box padding="none" marginBottom="spacingXl">
<Form onSubmit={submitForm}>
<FormControl>
<FormControl.Label isRequired>Name</FormControl.Label>
<TextInput />
<FormControl.HelpText>
Please enter your first name
</FormControl.HelpText>
</FormControl>
<FormControl>
<FormControl.Label>Description</FormControl.Label>
<Textarea />
<FormControl.HelpText>
Tell me about yourself
</FormControl.HelpText>
</FormControl>
<Button variant="primary" type="submit" isDisabled={submitting}>
{submitting ? 'Submitted' : 'Click me to submit'}
</Button>
</Form>
</Box>
</Layout.Body>
</Layout>
);
}

Layout with right sidebar

function BasicLayoutExample() {
const [submitting, setSubmitting] = useState(false);
const submitForm = () => {
setSubmitting(true);
setTimeout(() => setSubmitting(false), 1000);
};
return (
<Layout
rightSidebar={
<Layout.Sidebar>
<Box padding="none" marginBottom="spacingXl">
<Paragraph>Sidebar Content</Paragraph>
</Box>
</Layout.Sidebar>
}
>
<Layout.Body>
<Box padding="none" marginBottom="spacingXl">
<Form onSubmit={submitForm}>
<FormControl>
<FormControl.Label isRequired>Name</FormControl.Label>
<TextInput />
<FormControl.HelpText>
Please enter your first name
</FormControl.HelpText>
</FormControl>
<FormControl>
<FormControl.Label>Description</FormControl.Label>
<Textarea />
<FormControl.HelpText>
Tell me about yourself
</FormControl.HelpText>
</FormControl>
<Button variant="primary" type="submit" isDisabled={submitting}>
{submitting ? 'Submitted' : 'Click me to submit'}
</Button>
</Form>
</Box>
</Layout.Body>
</Layout>
);
}

Layout with header and sidebars

function BasicLayoutExample() {
const [submitting, setSubmitting] = useState(false);
const submitForm = () => {
setSubmitting(true);
setTimeout(() => setSubmitting(false), 1000);
};
return (
<Layout
header={
<Layout.Header>
<Header title="Your Details" />
</Layout.Header>
}
leftSidebar={
<Layout.Sidebar>
<Box padding="none" marginBottom="spacingXl">
<Paragraph>Sidebar Content</Paragraph>
</Box>
</Layout.Sidebar>
}
rightSidebar={
<Layout.Sidebar>
<Box padding="none" marginBottom="spacingXl">
<Paragraph>Sidebar Content</Paragraph>
</Box>
</Layout.Sidebar>
}
>
<Layout.Body>
<Box padding="none" marginBottom="spacingXl">
<Form onSubmit={submitForm}>
<FormControl>
<FormControl.Label isRequired>Name</FormControl.Label>
<TextInput />
<FormControl.HelpText>
Please enter your first name
</FormControl.HelpText>
</FormControl>
<FormControl>
<FormControl.Label>Description</FormControl.Label>
<Textarea />
<FormControl.HelpText>
Tell me about yourself
</FormControl.HelpText>
</FormControl>
<Button variant="primary" type="submit" isDisabled={submitting}>
{submitting ? 'Submitted' : 'Click me to submit'}
</Button>
</Form>
</Box>
</Layout.Body>
</Layout>
);
}

Full Screen Layout with header and sidebars

function BasicLayoutExample() {
const [submitting, setSubmitting] = useState(false);
const submitForm = () => {
setSubmitting(true);
setTimeout(() => setSubmitting(false), 1000);
};
return (
<Layout
variant="fullscreen"
header={
<Layout.Header>
<Header title="Your Details" />
</Layout.Header>
}
leftSidebar={
<Layout.Sidebar>
<Box padding="none" marginBottom="spacingXl">
<Paragraph>Sidebar Content</Paragraph>
</Box>
</Layout.Sidebar>
}
rightSidebar={
<Layout.Sidebar>
<Box padding="none" marginBottom="spacingXl">
<Paragraph>Sidebar Content</Paragraph>
</Box>
</Layout.Sidebar>
}
>
<Layout.Body>
<Box padding="none" marginBottom="spacingXl">
<Form onSubmit={submitForm}>
<FormControl>
<FormControl.Label isRequired>Name</FormControl.Label>
<TextInput />
<FormControl.HelpText>
Please enter your first name
</FormControl.HelpText>
</FormControl>
<FormControl>
<FormControl.Label>Description</FormControl.Label>
<Textarea />
<FormControl.HelpText>
Tell me about yourself
</FormControl.HelpText>
</FormControl>
<Button variant="primary" type="submit" isDisabled={submitting}>
{submitting ? 'Submitted' : 'Click me to submit'}
</Button>
</Form>
</Box>
</Layout.Body>
</Layout>
);
}

Layout areas

The Layout component offers 4 individual areas, which can be set via the props header, leftSidebar, rightSidebar, and as children (for the main content area).

PropDescriptionRecommended Child components
childrenElements handed over as children to the Layout component render as the Layout's body. Ideally, all children should be wrapped inside Layout.BodyLayout.Body
headerElements in the header overarch the whole width of the layout component. Child components should be wrapped inside Layout.Header. It is also recommended to use Header as the only child of Layout.HeaderLayout.Header with Header as a child
leftSidebar | rightSidebarThese child-components render on the left and right side of the body content. They should be wrapped in Layout.SidebarLayout.Sidebar

Note When passing at least one sidebar, a divider is added underneath the header. There is no divider otherwise.

Accessibility

  • The Layout component renders a <section> by default. If you use multiple layouts or want to improve landmark navigation, provide a unique aria-label
  • Layout.Sidebar renders as a semantic <aside> by default
  • Layout.Header renders as a semantic <header> by default
  • Keyboard navigation and focus management for interactive content inside the layout should be implemented by the consumer.

Props (API reference)

Open in Storybook

Layout

Name

Type

Default

children
ReactNode

The body of the layout.

className
string

CSS class to be appended to the root element

contentClassName
string

Classname that will be passed to the main content div, which holds the sidebars and children div

contentTestId
string

css
string
number
false
true
ComponentSelector
Keyframes
SerializedStyles
ArrayInterpolation<undefined>
ObjectInterpolation<undefined>
(theme: any) => Interpolation<undefined>

header
string
number
false
true
{}
ReactElement<any, string | JSXElementConstructor<any>>
ReactNodeArray
ReactPortal

leftSidebar
string
number
false
true
{}
ReactElement<any, string | JSXElementConstructor<any>>
ReactNodeArray
ReactPortal

leftSidebarVariant
"narrow"
"wide"

Defines the width of the layout left sidebar.

'narrow' (280px)
offsetTop
number

Offset for layout heights calculation. Set to `0` for layout usage without navbar.

60 (= navbar height)
rightSidebar
string
number
false
true
{}
ReactElement<any, string | JSXElementConstructor<any>>
ReactNodeArray
ReactPortal

rightSidebarVariant
"narrow"
"wide"

Defines the width of the layout right sidebar.

'wide' (340px)
testId
string

A [data-test-id] attribute used for testing purposes

variant
"narrow"
"wide"
"fullscreen"

Defines the width of the layout and its content.

'wide'
withBoxShadow
false
true

Layout.Body

Layout.Header

Layout.Sidebar