> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Redefining Layout in Anvil2

export const BlogMeta = ({date, author, tags}) => {
  const formatList = items => {
    if (!Array.isArray(items)) return items;
    if (items.length === 1) return items[0];
    if (items.length === 2) return `${items[0]} & ${items[1]}`;
    return `${items.slice(0, -1).join(", ")}, & ${items[items.length - 1]}`;
  };
  return <div className="flex flex-wrap items-center gap-2 text-sm text-gray-500 dark:text-gray-400">
      <span>{date}</span>
      <span>|</span>
      <span>{formatList(author)}</span>
      {tags && tags.length > 0 && <>
          <span>|</span>
          <div className="flex flex-wrap gap-1.5">
            {tags.map(tag => <span key={tag} className="px-2 py-1 rounded bg-gray-100 dark:bg-neutral-800 text-xs">
                {tag}
              </span>)}
          </div>
        </>}
    </div>;
};

<BlogMeta date="August 16, 2024" author="Derek Watson" tags={["Engineering", "How To", "Web"]} />

In Anvil2, we have introduced new components and features to make creating dynamic, responsive page layouts a breeze. Read on to learn more!

Fork [this codesandbox](https://codesandbox.io/p/sandbox/anvil2-layout-demo-vl5fcv) to play around with some of the new features! This was used during a tech talk on July 2nd, 2024.

## Layout changes from Anvil → Anvil2

### Summary

* Enable easy use of Flexbox and CSS Grid
  * Two new component – Flex and Grid
  * All Anvil2 components have some control over layout using layout utils props
* Simplified APIs
* Flexibility and responsiveness baked-in

### Page component updates

*See [Anvil2 Page Implementation Docs](/docs/web/components/page/code)*

* Simplified API
* Headers, footers, and action toolbars should now be created independently as part of the layout
* Sidebar and Panel are now sub-components
* Background color can be controlled using CSS (`style` or `className`)
* Better responsive behavior coming soon!

```tsx theme={null}
<Page>
  <Page.Sidebar>
    <Page.SidebarHeader>
      <Text variant="headline" el="h2">
        Sidebar Header
      </Text>
    </Page.SidebarHeader>
    <SideNav>
      <SideNav.Link id="01" href="#">
        Nav Link
      </SideNav.Link>
    </SideNav>
  </Page.Sidebar>
  <Page.Content>
    {/* page content (including the header, action toolbar, footer, etc.) */}
  </Page.Content>
</Page>
```

### Layout component updates

*See [Anvil2 Layout Implementation Docs](/docs/web/components/layout/code)*

* Simplified API with `Layout` and `Layout.Item` used to create columns
* Responsiveness built-in, and customizable
* Three density variants available using `variant` prop: `"default"`, `"narrow"`, and `"wide"`

```tsx theme={null}
<Layout variant="narrow">
  <Layout.Item span={12}>{/\* full-width content... \*/}</Layout.Item>
  <Layout.Item span={3}>{/\* one-quarter-width content... \*/}</Layout.Item>
  <Layout.Item span={9}>{/\* three-quarter-width content... \*/}</Layout.Item>
</Layout>
```

#### Column structure and responsive behavior​

Layouts use a 12-column structure that reduces columns based on the size of the layout. Note that the values below are based on the width of the Layout, not the entire screen (using container queries). This is important if the page includes a sidebar or panel.

* On `sm` screens (and below), there are four columns
* On `md` screens and up, there are twelve columns

Responsive props can be used to override the `span` value at certain breakpoints (and higher).

```tsx theme={null}
<Layout.Item
  // <640px = full-width
  span={4}
  // 640px -> 767px = 3/4 width
  sm={3}
  // 768px -> 1023px = 1/3 width
  md={4}
  // 1024px -> 1279px = 1/2 width
  lg={6}
  // 1280px -> 1535px = 2/3 width
  xl={8}
  // >=1536px = 3/4 width
  xxl={9}
>
  {/*...content */}
</Layout.Item>
```

## New layout features in Anvil2

### Flex and Grid components

*See the [Flex Implementation Docs](/docs/web/components/flex/code) and [Grid Implementation Docs](/docs/web/components/grid/code).*

`Flex` is similar to `Stack`, with some minor differences. A `Flex` can be used both as a flex container and item, so instead of using `Stack.Item`, use another `Flex` or another Anvil2 component. This greatly reduces the amount of code required to build flex layouts!

#### Anvil (legacy) example

```tsx theme={null}
<Stack direction="column" alignItems="center">
  <Stack.Item>
    <Headline />
  </Stack.Item>
  <Stack.Item>
    <Stack spacing="1">
      <Stack.Item fill>
        <Text />
      </Stack.Item>
      <Stack.Item alignSelf="flex-start">
        <Button />
      </Stack.Item>
    </Stack>
  </Stack.Item>
</Stack>
```

#### Anvil2 example

```tsx theme={null}
<Flex direction="column" alignItems="center">
  <Text variant="headline" />
  <Flex gap="2">
    <Text flexGrow="1" />
    <Button alignSelf="flex-start" />
  </Flex>
</Flex>
```

The new `Grid` component can be used to create CSS Grid layouts (not to be confused with the Anvil `Grid`). `Grid` components can also be used as grid containers or items, and any Anvil2 component can use special grid props to control its columns and rows.

```tsx theme={null}
<Grid
  templateColumns="repeat(5, 1fr)"
  autoRows="minmax(3rem, auto)"
  columnGap="4"
  rowGap="2"
>
  <Card gridColumn="1 / 6" />
  <Card gridRow="2 / 5" />
  <Card gridArea="2 / 2 / 5 / 6" />
</Grid>
```

#### Responsive props of Flex and Grid​

Similar to the `Layout.Item`, responsive props are also available to override any of the `Flex` and `Grid` props at different breakpoints.

```tsx theme={null}
<Grid
  md={{ templateColumns: "repeat(5, 1fr)", columnGap: "4" }}
  autoRows="minmax(3rem, auto)"
  rowGap="2"
>
  <Card sm={{ gridColumn: "1 / 6" }} />
  <Card sm={{ gridRow: "2 / 5" }} />
  <Flex
    direction="column"
    alignItems="center"
    md={{ gridArea: "2 / 2 / 5 / 6" }}
  >
    <Text variant="headline" />
    <Flex gap="2">
      <Text flexGrow="1" />
      <Button alignSelf="flex-start" />
    </Flex>
  </Flex>
</Grid>
```

### Layout Props

S*ee [Layout Props Utilities documentation](/docs/web/utilities/layout-props).*

All Anvil2 components other than `Page` and `Layout` extend `Layout` type, which enable them to control various flex and grid properties. props at different breakpoints.

```tsx theme={null}
type Layout = {
    // flex only
    flex?: CSSProperties["flex"];
    flexDirection?: CSSProperties["flexDirection"];
    flexGrow?: CSSProperties["flexGrow"];
    flexShrink?: CSSProperties["flexShrink"];
    flexBasis?: CSSProperties["flexBasis"];

    // grid only
    gridArea?: CSSProperties["gridArea"];
    gridColumn?: CSSProperties["gridColumn"];
    gridRow?: CSSProperties["gridRow"];
    gridColumnStart?: CSSProperties["gridColumnStart"];
    gridColumnEnd?: CSSProperties["gridColumnEnd"];
    gridRowStart?: CSSProperties["gridRowStart"];
    gridRowEnd?: CSSProperties["gridRowEnd"];

    // both
    alignContent?: CSSProperties["alignContent"];
    alignItems?: CSSProperties["alignItems"];
    alignSelf?: CSSProperties["alignSelf"];
    columnGap?: “0” -> “14” | “half”;
    gap?: “0” -> “14” | “half”;
    justifyContent?: CSSProperties["justifyContent"];
    justifyItems?: CSSProperties["justifyItems"];
    justifySelf?: CSSProperties["justifySelf"];
    order?: CSSProperties["order"];
    placeContent?: CSSProperties["placeContent"];
    placeItems?: CSSProperties["placeItems"];
    placeSelf?: CSSProperties["placeSelf"];
    rowGap?: “0” -> “14” | “half”;

    // responsive overrides to all of the props above
    sm: Omit<Layout, "sm" | "md" | "lg" | "xl" | "xxl">
    md: Omit<Layout, "sm" | "md" | "lg" | "xl" | "xxl">
    lg: Omit<Layout, "sm" | "md" | "lg" | "xl" | "xxl">
    xl: Omit<Layout, "sm" | "md" | "lg" | "xl" | "xxl">
    xxl: Omit<Layout, "sm" | "md" | "lg" | "xl" | "xxl">
}
```

Several of the props in the `Layout` type only apply to flex or grid containers. The `Card` component is a flex container by default. Other components would need `display: flex` or `display: grid` added to use the following props:

```tsx theme={null}
type LayoutPropsForContainersOnly = {
    flexDirection?: CSSProperties["flexDirection"];
    alignContent?: CSSProperties["alignContent"];
    alignItems?: CSSProperties["alignItems"];
    columnGap?: “0” -> “14” | “half”;
    gap?: “0” -> “14” | “half”;
    justifyContent?: CSSProperties["justifyContent"];
    justifyItems?: CSSProperties["justifyItems"];
    placeContent?: CSSProperties["placeContent"];
    placeItems?: CSSProperties["placeItems"];
    rowGap?: “0” -> “14” | “half”;
}
```

## Putting it all together

These components and props work together to make creating flexible, responsive layouts a breeze in Anvil2!

```tsx theme={null}
const ExamplePage = () => {
  const [panelIsOpen, setPanelIsOpen] = useState(false);
  const gridData = [
    /*... some objects ...*/
  ];
  return (
    <Page>
      <Page.Sidebar>
        <Page.SidebarHeader>
          <Text variant="headline" el="h2">
            Sidebar Header
          </Text>
        </Page.SidebarHeader>
        <SideNav>
          <SideNav.Item id="1" active>
            First Page
          </SideNav.Item>
        </SideNav>
      </Page.Sidebar>
      <Page.Panel open={panelIsOpen}>{/* panel content */}</Page.Panel>
      <Page.Content>
        <Layout fluid>
          <Layout.Item span={12}>
            <Flex direction="column" gap="2" md={{ direction: "row" }}>
              <Text variant="headline" el="h1" md={{ flexGrow: "1" }}>
                Page Title
              </Text>
              <Card direction="column" md={{ alignSelf: "flex-start" }}>
                <Text variant="eyebrow">Card header</Text>
                <Text>Card content</Text>
              </Card>
            </Flex>
          </Layout.Item>
          <Layout.Item span={4} md={5} lg={4}>
            {/*  small column content      */}
            {/*  xs/sm     =   full-width  */}
            {/*  md        =   5/12 width   */}
            {/*  lg/xl/xxl =   1/3 width   */}
          </Layout.Item>
          <Layout.Item span={4} md={7} lg={8}>
            {/*  large column content      */}
            {/*  xs/sm     =   full-width  */}
            {/*  md        =   7/12 width   */}
            {/*  lg/xl/xxl =   2/3 width   */}
            <Grid
              gap="2"
              sm={{ templateColumns: "repeat(2, 1fr)" }}
              md={{ templateColumns: "repeat(3, 1fr)" }}
              xl={{ templateColumns: "repeat(4, 1fr)" }}
            >
              {gridData.map((item) => (
                <Card>{/* render gridData item */}</Card>
              ))}
            </Grid>
          </Layout.Item>
        </Layout>
      </Page.Content>
    </Page>
  );
};
```
