Introduction
Let us continue building our chakra components using styled-components & styled-system. In this tutorial we will be cloning the Chakra UI SimpleGrid component.
- I would like you to first check the chakra docs for simplegrid.
- We will compose (extend) our
Gridcomponent to create theSimpleGridcomponent. This component is an easy to get started component that does not have the complexities of CSS Grid. - All the code for this tutorial can be found here under the atom-layout-grid branch.
Prerequisite
Please check the previous post where we have completed the Grid & GridItem Components. Also please check the Chakra SimpleGrid Component code here. In this tutorial we will -
- Create a SimpleGrid component.
- Create story for the SimpleGrid component.
Setup
- First let us create a branch, from the main branch run -
git checkout -b atom-layout-grid
Under grid folder create
simplegrid.tsxfile.So our folder structure stands like - src/components/atoms/layout/grid.
SimpleGrid Component
- Now this is really interesting. Let me list the props that this component takes in : -
- columns: - The number of columns you want.
- spacing: - The gap (both vertical and horizontal) between the grid items.
- spacingX: - The horizontal gap between the grid items.
- spacingY: - The vertical gap between the grid items.
- minChildWidth: - The width at which child elements will break into columns. We pass a number for pixel values or a string for any other valid CSS length.
- Let me paste the code for you, if you read the last
Gridcomponent post, you will get this code.
import * as React from "react";
import { ResponsiveValue } from "styled-system";
import { isNumber, isNull, mapResponsive } from "../../../../utils";
import { Grid, GridProps } from "./grid";
function toPx(value: string | number) {
return isNumber(value) ? `${value}px` : value;
}
function widthToColumns(width: any) {
return mapResponsive(width, (value) =>
isNull(value) ? null : `repeat(auto-fit, minmax(${toPx(value)}, 1fr))`
);
}
function countToColumns(count: any) {
return mapResponsive(count, (value) =>
isNull(value) ? null : `repeat(${value}, minmax(0, 1fr))`
);
}
export interface SimpleGridOptions {
minChildWidth?: GridProps["minWidth"];
columns?: ResponsiveValue<number>;
spacing?: GridProps["gap"];
spacingX?: GridProps["gap"];
spacingY?: GridProps["gap"];
}
export interface SimpleGridProps extends GridProps, SimpleGridOptions {}
export const SimpleGrid = React.forwardRef<HTMLDivElement, SimpleGridProps>(
(props, ref) => {
const {
columns,
spacingX,
spacingY,
spacing,
minChildWidth,
...delegated
} = props;
const templateColumns = minChildWidth
? widthToColumns(minChildWidth)
: countToColumns(columns);
return (
<Grid
ref={ref}
gap={spacing}
columnGap={spacingX}
rowGap={spacingY}
templateColumns={templateColumns}
{...delegated}
/>
);
}
);
I would like to draw your attention to the
templateColumnsvariable, if you pass the propminChildWidthwe will useauto-fitbecause we don't know the number of columns.But if we pass
columns(number of columns) we use the column value to create our columns. Now you should know some CSS Grid to understand this. It is pretty straightforward.Look how easy, clear is this API. Try to push yourself for a clean and easy to use API. It won't happen in the first attempt but take inspiration from open source libraries like Chakra UI, read their code. Because many people contribute to these libraries and they bring a lot of ideas which we can learn from.
Story
- With the above our
GridandGridItemcomponents are completed, let us create a story. - Under the
src/components/atoms/layout/grid/grid.stories.tsxfile we add the below story code. - We will create another story called simpleGrid.
import { spacingOptions } from "../../../../theme/spacing";
import { SimpleGrid, SimpleGridProps } from "./simplegrid";
export const simpleGrid = {
argTypes: {
minChildWidth: {
name: "minChildWidth",
type: { name: "string", required: false },
defaultValue: "170px",
description: `The width at which child elements will
break into columns. Pass a number for pixel values
or a string for any other valid CSS length.`,
table: {
type: { summary: "string" },
defaultValue: { summary: "-" },
},
},
spacingY: {
name: "spacingY",
type: { name: "string", required: false },
defaultValue: "md",
description: "The column gap between the grid items.",
table: {
type: { summary: "string" },
defaultValue: { summary: "-" },
},
control: {
type: "select",
...spacingOptions(),
},
},
spacingX: {
name: "spacingX",
type: { name: "string", required: false },
defaultValue: "lg",
description: "The row gap between the grid items.",
table: {
type: { summary: "string" },
defaultValue: { summary: "-" },
},
control: {
type: "select",
...spacingOptions(),
},
},
},
render: (args: SimpleGridProps) => (
<SimpleGrid {...args}>
<GridItem bg="tomato" height="80px" />
<GridItem bg="tomato" height="80px" />
<GridItem bg="tomato" height="80px" />
<GridItem bg="tomato" height="80px" />
<GridItem bg="tomato" height="80px" />
<GridItem bg="tomato" height="80px" />
</SimpleGrid>
),
};
- Now run
npm run storybookcheck the stories.
Build the Library
- Under the
/layout/grid/index.tspaste the following -
export * from "./grid";
export * from "./simplegrid";
Now
npm run build.Under the folder
example/src/App.tsxwe can test ourGridcomponent. Copy paste the following code and runnpm run startfrom theexampledirectory.
import * as React from "react";
import { SimpleGrid, Box } from "chakra-ui-clone";
export function App() {
return (
<SimpleGrid columns={2} spacingX="40px" spacingY="20px">
<Box bg="tomato" height="80px"></Box>
<Box bg="tomato" height="80px"></Box>
<Box bg="tomato" height="80px"></Box>
<Box bg="tomato" height="80px"></Box>
<Box bg="tomato" height="80px"></Box>
</SimpleGrid>
);
}
Summary
There you go guys in this tutorial we created SimpleGrid component just like chakra ui and stories for them. You can find the code for this tutorial under the atom-layout-grid branch here. In the next tutorial we will create Text component. Until next time PEACE.
Top comments (0)