2024June

shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 1

In this article, I discuss how Blocks page is built on ui.shadcn.com. Blocks page has a lot of utilities used, hence I broke down this Blocks page analysis into 5 parts.

  1. shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 1

  2. shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 2 (Coming soon)

  3. shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 3 (Coming soon)

  4. shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 4 (Coming soon)

  5. shadcn-ui/ui codebase analysis: How is “Blocks” page built — Part 5 (Coming soon)

In part 1, we will look at the following:

  1. Where to find blocks page code in the shadcn-ui/ui repository?

  2. getAllBlockIds function

  3. _getAllBlocks function

These function further call other utility functions that will be explained in the other parts.

Where to find blocks page code in the shadcn-ui/ui repository?

blocks/page.tsx is where you will find Blocks page related code in the shadcn-ui/ui repository

Just because it has only 10 lines of code does not mean it is a simple page, there is a lot going on behind these lines, especially in the lib/blocks.ts, but don’t worry, we will understand the utility functions used in depth later in this article and other parts as well.

BlocksPage gets the blocks from a function named getAllBlockIds() which is imported from lib/blocks and these blocks are mapped with a BlockDisplay component that shows blocks on the Blocks page. Let’s find out what is in getAllBlockIds()

getAllBlockIds function

The below code snippet is picked from lib/blocks.ts

export async function getAllBlockIds(
  style: Style["name"] = DEFAULT_BLOCKS_STYLE
) {
  const blocks = await _getAllBlocks(style)
  return blocks.map((block) => block.name)
}

This code snippet is self explanatory, style parameter gets a default value DEFAULT_BLOCKS_STYLE because in the Blocks page, we call getAllBlockIds without any params as shown below:

const blocks = await getAllBlockIds()

But wait, what is the value in DEFAULT_BLOCKS_STYLE?

At line 14 in lib/blocks, you will find this below code:

const DEFAULT_BLOCKS_STYLE = "default" satisfies Style["name"]

“default” satisfies Style[“name”], Style is from register/styles. I just admire the quality of Typescript written in this shadcn-ui/ui. So, getAllBlocks gets called with a param named style that is initiated to “default”. So far, the code is straight forward. Let’s now understand what is in getAllBlocks

_getAllBlocks function

The below code snippet is picked from lib/blocks.ts

async function _getAllBlocks(style: Style["name"] = DEFAULT_BLOCKS_STYLE) {
  const index = z.record(registryEntrySchema).parse(Index[style])
 
  return Object.values(index).filter(
    (block) => block.type === "components:block"
  )
}

Even though, getAllBlockIds from above calls this function with a parameter, this function still has a default value set to the style parameter.

const index = z.record(registryEntrySchema).parse(Index[style])

Code above has the following:

z.record

Record schema in Zod are used to validate types such as Record<string, number>. This is particularly useful for storing or caching items by ID.

registryEntrySchema

registryEntrySchema defines a schema for the blocks

export const registryEntrySchema = z.object({
  name: z.string(),
  description: z.string().optional(),
  dependencies: z.array(z.string()).optional(),
  devDependencies: z.array(z.string()).optional(),
  registryDependencies: z.array(z.string()).optional(),
  files: z.array(z.string()),
  source: z.string().optional(),
  type: z.enum([
    "components:ui",
    "components:component",
    "components:example",
    "components:block",
  ]),
  category: z.string().optional(),
  subcategory: z.string().optional(),
  chunks: z.array(blockChunkSchema).optional(),
})

parse(Index[style])

parse is a schema method to check data is valid. If it is, a value is returned with full type information! Otherwise, an error is thrown.

Example:

const stringSchema = z.string();
 
stringSchema.parse("fish"); // => returns "fish"
stringSchema.parse(12); // throws error

Index is imported from registryfolder and contains all the components used in shadcn-ui/ui.

Looks like this file gets auto generated by scripts/build-registry.ts and this is also used in CLI package to add shadcn components into your project, more on this in the upcominhg articles.

Basically, we validate Index[“default”] against the registry schema to ensure the auto generated code is valid and is ready for further processing such as showing in blocks page.

_getAllBlocks filters the blocks based on the block type as shown below:

return Object.values(index).filter(
    (block) => block.type === "components:block"
  )

This is how you are able to see components that are specific to Blocks page.

Conclusion:

We looked at two important module functions named getAllBlockIds and _getAllBlocks. I find this code to be pretty self explanatory, I do admire the way zod’s Record schema validations are used on the auto generated registry index json.

Want to learn how to build shadcn-ui/ui from scratch? Check out build-from-scratch

About me:

Hey, my name is Ramu Narasinga. I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.

I am open to work on interesting projects. Send me an email at ramu.narasinga@gmail.com

My Github — https://github.com/ramu-narasinga

My website — https://ramunarasinga.com

My Youtube channel — https://www.youtube.com/@thinkthroo

Learning platform — https://thinkthroo.com

Codebase Architecture — https://app.thinkthroo.com/architecture

Best practices — https://app.thinkthroo.com/best-practices

Production-grade projects — https://app.thinkthroo.com/production-grade-projects

References:

  1. https://github.com/shadcn-ui/ui/blob/main/apps/www/app/(app)/blocks/page.tsx

  2. https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L20

  3. https://github.com/shadcn-ui/ui/blob/main/apps/www/lib/blocks.ts#L75

  4. https://github.com/shadcn-ui/ui/blob/main/apps/www/registry/schema.ts#L16

We use cookies
We use cookies to ensure you get the best experience on our website. For more information on how we use cookies, please see our cookie policy.

By clicking "Accept", you agree to our use of cookies.

Learn more