DEV Community

Arsalan Ahmed Yaldram
Arsalan Ahmed Yaldram

Posted on • Updated on

Build Chakra UI Container components using react, typescript, styled-components and styled-system

Introduction

Let us continue building our chakra components using styled-components & styled-system. Chakra UI has some pretty neat container components namely Square, Center, Circle and Container.

  • I would like you to first check the [chakra docs] for each of the components here.

  • We will compose (extend) our Flex component to create these components.

  • All the code for this tutorial can be found here under the atom-layout-containers branch.

Prerequisite

Please check the previous post where we have completed the Stack Component. Also please check the Chakra Component code here. In this tutorial we will -

  • Create a Square component.
  • Create a Circle component.
  • Create a Center component.
  • Create a Container component.
  • Create their respective stories.

Setup

  • First let us create a branch, from the main branch run -
git checkout -b atom-layout-containers
Enter fullscreen mode Exit fullscreen mode
  • Under the components/atoms/layout folder create a new folder called containers. Under containers folder create 2 files index.tsx and containers.stories.tsx.

  • So our folder structure stands like - src/components/atoms/layout/containers.

Square Component

This component will center its child given size (width and height). We can also pass centerContent = false prop if we don't want to center content.

import * as React from "react";

import { Flex, FlexProps } from "../flex";

type SqureOmitted = "width" | "height" | "w" | "h";

export interface SquareProps extends Omit<FlexProps, SqureOmitted> {
  centerContent?: boolean;
}

export const Square = React.forwardRef<HTMLDivElement, SquareProps>(
  (props, ref) => {
    const { size, centerContent = true, children, ...delegated } = props;

    const squareProps = centerContent && {
      align: "center",
      justify: "center",
    };

    return (
      <Flex
        ref={ref}
        size={size}
        {...squareProps}
        grow={0}
        shrink={0}
        {...delegated}
      >
        {children}
      </Flex>
    );
  }
);
Enter fullscreen mode Exit fullscreen mode

For simplicity we omitted height and width props instead simply pass the size prop.

Circle Component

We extend the Square Component with a round border radius so that it appears like a Circle, this will come handy if you want to display some icons under a circle.

export const Circle = React.forwardRef<HTMLDivElement, SquareProps>(
  (props, ref) => {
    const { size, children, ...delegated } = props;

    return (
      <Square ref={ref} size={size} {...delegated} borderRadius="9999px">
        {children}
      </Square>
    );
  }
);
Enter fullscreen mode Exit fullscreen mode

Center Component

This component will center its child given width and height.

interface CenterProps
  extends Omit<FlexProps, "display" | "align" | "justify"> {}

export const Center = React.forwardRef<HTMLDivElement, CenterProps>(
  (props, ref) => {
    const { children, ...delegated } = props;

    return (
      <Flex ref={ref} align="center" justify="center" {...delegated}>
        {children}
      </Flex>
    );
  }
);
Enter fullscreen mode Exit fullscreen mode

Because as the name suggest this is a Center component, we omit the alignItems and justifyContent props and by default pass these with center values.

Container Component

This component is used to constrain a content's width to the current breakpoint, while keeping it fluid. It sets margin-left and margin-right to auto, to keep its content centered.

It also sets a default max-width of 60ch (60 characters), but you can customize this by passing custom maxWidth value. We can also pass centerContent = true prop if we want to center content inside the container.

export interface ContainerProps extends FlexProps {
  centerContent?: boolean;
}

export const Container = React.forwardRef<HTMLDivElement, ContainerProps>(
  (props, ref) => {
    const { children, centerContent, ...delegated } = props;

    const centerContentProps = centerContent && {
      align: "center",
    };

    return (
      <Flex
        ref={ref}
        width="100%"
        mx="auto"
        maxW="60ch"
        px="10px"
        direction="column"
        {...centerContentProps}
        {...delegated}
      >
        {children}
      </Flex>
    );
  }
);
Enter fullscreen mode Exit fullscreen mode

Story

  • With the above our Container components are completed, let us create a story.
  • Under the src/components/atoms/layout/containers/containers.stories.tsx file we add the below story code.
  • We will create 3 stories - center, square, container.
import * as React from "react";

import { HStack, VStack } from "../stack";
import { Container, Square, Circle, Center } from ".";

export default {
  title: "Atoms/Layout/Containers",
};

export const center = {
  render: () => (
    <Center bg="tomato" h="100px" color="white">
      This is the Center
    </Center>
  ),
};

export const square = {
  render: () => (
    <HStack spacing="4xl">
      <Square size="40px" bg="tomato" color="white">
        1
      </Square>
      <Square
        as="span"
        size="40px"
        bg="tomato"
        color="white"
        centerContent={false}
      >
        2
      </Square>
      <Circle size="40px" bg="tomato" color="white">
        3
      </Circle>
    </HStack>
  ),
};

export const container = {
  render: () => (
    <VStack spacing="4xl">
      <Container color="white" p="md" bg="red500" maxW="900px">
        Not Centered Content
      </Container>
      <Container p="md" bg="yellow200" maxW="900px" centerContent>
        Centered Content
      </Container>
    </VStack>
  ),
};
Enter fullscreen mode Exit fullscreen mode

Build the Library

  • Under the /layout/index.ts file and paste the following -
export * from "./box";
export * from "./flex";
export * from "./stack";
export * from "./containers";
Enter fullscreen mode Exit fullscreen mode
  • Now npm run build.

  • Under the folder example/src/App.tsx we can test our Box component. Copy paste the following code and run npm run start from the example directory.

import * as React from "react";
import { HStack, Square, Circle } from "chakra-ui-clone";

export function App() {
  return (
    <HStack spacing="4xl">
      <Square size="40px" bg="tomato" color="white">
        1
      </Square>
      <Square
        as="span"
        size="40px"
        bg="tomato"
        color="white"
        centerContent={false}
      >
        2
      </Square>
      <Circle size="40px" bg="tomato" color="white">
        3
      </Circle>
    </HStack>
  );
}
Enter fullscreen mode Exit fullscreen mode

Summary

There you go guys in this tutorial we created Container components just like chakra ui and stories for them. You can find the code for this tutorial under the atom-layout-containers branch here. In the next tutorial we will create Wrap and WrapItem components. Until next time PEACE.

Discussion (0)