CatalystUI

DocsTemplates

Sheet

A sheet component using native card and Radix dialog.

Installations

Install radix-ui, clsx, and tailwind-merge to use avatar component.

npm install radix-ui clsx tailwind-merge

Add the following function in lib/utils

import clsx, { type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
 
export function cx(...args: ClassValue[]) {
  return twMerge(clsx(...args));
}

Copy paste the component

import * as React from "react";
import { Dialog as SheetPrimitives } from "radix-ui";
import { XIcon } from "lucide-react";
 
import { cx } from "@/lib/utils";
 
import { Button } from "./button";
 
const Sheet = (
  props: React.ComponentPropsWithoutRef<typeof SheetPrimitives.Root>
) => {
  return <SheetPrimitives.Root tremor-id="tremor-raw" {...props} />;
};
Sheet.displayName = "Sheet";
 
const SheetTrigger = React.forwardRef<
  React.ElementRef<typeof SheetPrimitives.Trigger>,
  React.ComponentPropsWithoutRef<typeof SheetPrimitives.Trigger>
>(({ className, ...props }, ref) => {
  return (
    <SheetPrimitives.Trigger ref={ref} className={cx(className)} {...props} />
  );
});
SheetTrigger.displayName = "Sheet.Trigger";
 
const SheetClose = React.forwardRef<
  React.ElementRef<typeof SheetPrimitives.Close>,
  React.ComponentPropsWithoutRef<typeof SheetPrimitives.Close>
>(({ className, ...props }, ref) => {
  return (
    <SheetPrimitives.Close ref={ref} className={cx(className)} {...props} />
  );
});
SheetClose.displayName = "Sheet.Close";
 
const SheetPortal = SheetPrimitives.Portal;
 
SheetPortal.displayName = "SheetPortal";
 
const SheetOverlay = React.forwardRef<
  React.ElementRef<typeof SheetPrimitives.Overlay>,
  React.ComponentPropsWithoutRef<typeof SheetPrimitives.Overlay>
>(({ className, ...props }, forwardedRef) => {
  return (
    <SheetPrimitives.Overlay
      ref={forwardedRef}
      className={cx(
        // base
        "fixed inset-0 z-50 overflow-y-auto",
        // background color
        "bg-black/30",
        // transition
        "data-[state=closed]:animate-hide data-[state=open]:animate-dialog-overlay-show",
        className
      )}
      {...props}
      style={{
        animationDuration: "400ms",
        animationFillMode: "backwards",
      }}
    />
  );
});
 
SheetOverlay.displayName = "SheetOverlay";
 
const SheetContent = React.forwardRef<
  React.ElementRef<typeof SheetPrimitives.Content>,
  React.ComponentPropsWithoutRef<typeof SheetPrimitives.Content>
>(({ className, ...props }, forwardedRef) => {
  return (
    <SheetPortal>
      <SheetOverlay>
        <SheetPrimitives.Content
          ref={forwardedRef}
          className={cx(
            // base
            "fixed inset-y-2 z-50 mx-auto flex w-[95vw] flex-1 flex-col overflow-y-auto rounded-md border p-4 shadow-lg focus:outline-hidden max-sm:inset-x-2 sm:inset-y-2 sm:right-2 sm:max-w-lg sm:p-6",
            // border color
            "border-gray-200 dark:border-gray-900",
            // background color
            "bg-white dark:bg-[#090E1A]",
            // transition
            "data-[state=closed]:animate-Sheet-slide-right-and-fade data-[state=open]:animate-Sheet-slide-left-and-fade",
            className
          )}
          {...props}
        />
      </SheetOverlay>
    </SheetPortal>
  );
});
 
SheetContent.displayName = "SheetContent";
 
const SheetHeader = React.forwardRef<
  HTMLDivElement,
  React.ComponentPropsWithoutRef<"div">
>(({ children, className, ...props }, ref) => {
  return (
    <div
      ref={ref}
      className="flex items-start justify-between gap-x-4 border-b border-gray-200 pb-4 dark:border-gray-900"
      {...props}
    >
      <div className={cx("mt-1 flex flex-col gap-y-1", className)}>
        {children}
      </div>
      <SheetPrimitives.Close asChild>
        <Button
          variant="ghost"
          className="aspect-square p-1 hover:bg-gray-100 dark:hover:bg-gray-400/10"
        >
          <XIcon className="w-6 h-6" aria-hidden="true" />
        </Button>
      </SheetPrimitives.Close>
    </div>
  );
});
 
SheetHeader.displayName = "Sheet.Header";
 
const SheetTitle = React.forwardRef<
  React.ElementRef<typeof SheetPrimitives.Title>,
  React.ComponentPropsWithoutRef<typeof SheetPrimitives.Title>
>(({ className, ...props }, forwardedRef) => (
  <SheetPrimitives.Title
    ref={forwardedRef}
    className={cx(
      // base
      "text-base font-semibold",
      // text color
      "text-gray-900 dark:text-gray-50",
      className
    )}
    {...props}
  />
));
 
SheetTitle.displayName = "SheetTitle";
 
const SheetBody = React.forwardRef<
  HTMLDivElement,
  React.ComponentPropsWithoutRef<"div">
>(({ className, ...props }, ref) => {
  return <div ref={ref} className={cx("flex-1 py-4", className)} {...props} />;
});
SheetBody.displayName = "Sheet.Body";
 
const SheetDescription = React.forwardRef<
  React.ElementRef<typeof SheetPrimitives.Description>,
  React.ComponentPropsWithoutRef<typeof SheetPrimitives.Description>
>(({ className, ...props }, forwardedRef) => {
  return (
    <SheetPrimitives.Description
      ref={forwardedRef}
      className={cx("text-gray-500 dark:text-gray-500", className)}
      {...props}
    />
  );
});
 
SheetDescription.displayName = "SheetDescription";
 
const SheetFooter = ({
  className,
  ...props
}: React.HTMLAttributes<HTMLDivElement>) => {
  return (
    <div
      className={cx(
        "flex flex-col-reverse border-t border-gray-200 pt-4 sm:flex-row sm:justify-end sm:space-x-2 dark:border-gray-900",
        className
      )}
      {...props}
    />
  );
};
 
SheetFooter.displayName = "SheetFooter";
 
export {
  Sheet,
  SheetBody,
  SheetClose,
  SheetContent,
  SheetDescription,
  SheetFooter,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
};

Usage

import {
  Sheet,
  SheetBody,
  SheetClose,
  SheetContent,
  SheetDescription,
  SheetFooter,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/library/components/ui/sheet";
 
function SheetView() {
  return (
    <div className="flex justify-center">
      <Sheet>
        <SheetTrigger asChild>
          <Button variant="secondary">Open Sheet</Button>
        </SheetTrigger>
        <SheetContent className="sm:max-w-xl z-100">
          <SheetHeader>
            <SheetTitle>Account Created Successfully</SheetTitle>
            <SheetDescription className="mt-1 text-sm">
              Your account has been created successfully. You can now login to
              your account. For more information, please contact us.
            </SheetDescription>
          </SheetHeader>
          <SheetBody>
            This is they body of the Sheet, content goes here.
          </SheetBody>
          <SheetFooter className="mt-6">
            <SheetClose asChild>
              <Button
                className="mt-2 w-full sm:mt-0 sm:w-fit"
                variant="secondary"
              >
                Go back
              </Button>
            </SheetClose>
            <SheetClose asChild>
              <Button className="w-full sm:w-fit">Ok, got it!</Button>
            </SheetClose>
          </SheetFooter>
        </SheetContent>
      </Sheet>
    </div>
  );
}

Next: Line Chart

Found a bug? Report here.