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
Grid
component to create theSimpleGrid
component. 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.tsx
file.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
Grid
component 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
templateColumns
variable, if you pass the propminChildWidth
we will useauto-fit
because 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
Grid
andGridItem
components are completed, let us create a story. - Under the
src/components/atoms/layout/grid/grid.stories.tsx
file 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 storybook
check the stories.
Build the Library
- Under the
/layout/grid/index.ts
paste the following -
export * from "./grid";
export * from "./simplegrid";
Now
npm run build
.Under the folder
example/src/App.tsx
we can test ourGrid
component. Copy paste the following code and runnpm run start
from theexample
directory.
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)