Import
import { Layout } from '@contentful/f36-components';// orimport { Layout } from '@contentful/f36-layout';
Layout Compound Components
The Layout exports the following compound components
Compound Component | Description | Typical Usage Area |
|---|---|---|
Layout.Header | Should contain a | header |
Layout.HeaderInner | The HeaderInner component exposes a way to build visually consistent hierarchy into apps that look and feel like part of the Contentful UI. It’s the responsive variant of the Header component. | header |
Layout.Sidebar | Allows for variants | leftSidebar, rightSidebar |
Layout.Body | Wrapper around all children, this compound component is essential for proper overflow and scrolling behaviors. | wrapper around all children of 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 responsive header
function BasicLayoutExample() {const [submitting, setSubmitting] = useState(false);const submitForm = () => {setSubmitting(true);setTimeout(() => setSubmitting(false), 1000);};return (<Layoutheader={<Layout.Header><Layout.HeaderInnertitle="Your Details"actions={<Flex gap="spacingS"><Button variant="primary" size="small">Autofill with Provider 1</Button><Button variant="primary" size="small">Autofill with Provider 2</Button></Flex>}withBackButtonbreadcrumbs={[{ content: 'Account Settings', url: '#' }]}/></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 |
header | Elements in the header overarch the whole width of the layout component.
Child components should be wrapped inside | 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 |
** 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 | |
| header | string number bigint false true ReactElement<unknown, string | JSXElementConstructor<any>> Iterable<ReactNode> ReactPortal Promise<AwaitedReactNode> | |
| leftSidebar | string number bigint false true ReactElement<unknown, string | JSXElementConstructor<any>> Iterable<ReactNode> ReactPortal Promise<AwaitedReactNode> | |
| 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 bigint false true ReactElement<unknown, string | JSXElementConstructor<any>> Iterable<ReactNode> ReactPortal Promise<AwaitedReactNode> | |
| 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
Name | Type | Default |
|---|---|---|
| children | ReactNode | |
| className | string CSS class to be appended to the root element | |
| testId | string A [data-test-id] attribute used for testing purposes |
Layout.Header
Name | Type | Default |
|---|---|---|
| children | ReactNode | |
| className | string CSS class to be appended to the root element | |
| testId | string A [data-test-id] attribute used for testing purposes |
Layout.HeaderInner
Name | Type | Default |
|---|---|---|
| title required | string The title of the element this header pertains to. | |
| actions | ReactElement<unknown, string | JSXElementConstructor<any>> ReactElement<unknown, string | JSXElementConstructor<any>>[] Optional JSX children to display as complementary actions (e.g. buttons) related to the current page/route. | |
| backButtonProps | BackButtonProps Ensure that backbutton props can not be passed when `withBackButton` is false. This is to prevent confusion, as the back button will not be rendered. Props to spread on the back button. You almost certainly want to pass an `onClick` handler. | |
| breadcrumbs | Breadcrumb[] An (optional) list of navigable links to prepend to the current title. | |
| className | string CSS class to be appended to the root element | |
| metadata | string number bigint false true ReactElement<unknown, string | JSXElementConstructor<any>> Iterable<ReactNode> ReactPortal Promise<AwaitedReactNode> | |
| testId | string A [data-test-id] attribute used for testing purposes | |
| titleProps | { as?: HeadingElement; size?: "medium" | "large"; } | |
| withBackButton | false true If `true`, renders a leading back button within the header. |
Layout.Sidebar
Name | Type | Default |
|---|---|---|
| children | ReactNode | |
| className | string CSS class to be appended to the root element | |
| testId | string A [data-test-id] attribute used for testing purposes |