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 Component | Description | Typical Usage Area |
|---|---|---|
Layout.Header | Should 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.Sidebar | Allows for variants narrow (sets width: 280px) and wide (default, sets width: 340px). Both sidebars can have different widths. | leftSidebar, rightSidebar |
Layout.Body | Wrapper 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';// orimport { 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 (<Layoutheader={<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 (<LayoutleftSidebar={<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 (<LayoutrightSidebar={<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 (<Layoutheader={<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 (<Layoutvariant="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).
| Prop | Description | Recommended Child components |
|---|---|---|
children | Elements handed over as children to the Layout component render as the Layout's body. Ideally, all children should be wrapped inside Layout.Body | Layout.Body |
header | Elements 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.Header | Layout.Header with Header as a child |
leftSidebar | rightSidebar | These child-components render on the left and right side of the body content. They should be wrapped in Layout.Sidebar | Layout.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.Sidebarrenders as a semantic<aside>by defaultLayout.Headerrenders 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 StorybookLayout
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 |