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 ( <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 responsive header
function BasicLayoutExample() { const [submitting, setSubmitting] = useState(false); const submitForm = () => { setSubmitting(true); setTimeout(() => setSubmitting(false), 1000); }; return ( <Layout header={ <Layout.Header> <Layout.HeaderInner title="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> } withBackButton breadcrumbs={[{ 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 ( <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).
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 ReactElement<unknown, string | JSXElementConstructor<any>> 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 |