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.Sidebar
renders as a semantic<aside>
by defaultLayout.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 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 |