# Dashboard Layout 02 - RTL Layout

> Supports right to left languages with a layout designed for Arabic, Hebrew, and multilingual applications. Build localized dashboards without restructuring your entire interface.

A shadcn/ui block from the [@shadcn-dashboard](https://shadcndashboard.dev) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/shadcn-dashboard/dashboard-layout-02).

- Page, with a live preview: https://shadcn.exchange/r/shadcn-dashboard/dashboard-layout-02
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/shadcn-dashboard/dashboard-layout-02-light-7579e0183d2d3727.png
- Registry item: https://shadcndashboard.dev/r/dashboard-layout-02.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://shadcndashboard.dev/r/dashboard-layout-02.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `lucide-react`
- Registry items: `sidebar`, `scroll-area`, `collapsible`, `card`, `button`

## Files

### `src/components/shadcn-dashboard/blocks/dashboard-layout/dashboard-layout-02/page.tsx`

```tsx
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
import { AppSidebar } from "@/components/shadcn-dashboard/blocks/dashboard-layout/dashboard-layout-02/app-sidebar";

const Page = () => {
  return (
    <SidebarProvider dir="rtl">
      <AppSidebar />
      {/* ---------------- Main ---------------- */}
      <div className="flex flex-1 flex-col">
        <header className="sticky top-0 z-50 flex h-14 items-center border-b px-4 bg-background">
          <SidebarTrigger className="cursor-pointer"/>
        </header>
        <main className="flex-1 p-4" />
      </div>
    </SidebarProvider>
  );
};

export default Page;
```

### `src/components/shadcn-dashboard/blocks/dashboard-layout/dashboard-layout-02/app-sidebar.tsx`

```tsx
"use client";

import {
  Sidebar,
  SidebarContent,
  SidebarGroup,
  SidebarGroupContent,
  SidebarHeader,
  SidebarMenu,
  SidebarMenuButton,
  SidebarMenuItem,
} from "@/components/ui/sidebar";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Button } from "@/components/ui/button";
import {
  NavItem,
  NavMain,
} from "@/components/shadcn-dashboard/blocks/dashboard-layout/dashboard-layout-02/nav-main";
import {
  AlignStartVertical,
  PieChart,
  CircleUserRound,
  ClipboardList,
  Notebook,
  NotepadText,
  Table,
  Languages,
  Ticket,
  Rocket,
  LifeBuoy,
  BookOpen,
} from "lucide-react";

export const navData: NavItem[] = [
  // Dashboards Section
  { label: "لوحات التحكم", isSection: true },
  { title: "التحليلات", icon: PieChart, href: "#" },
  { title: "لوحة تحكم CRM", icon: ClipboardList, href: "#" },

  // Pages Section
  { label: "الصفحات", isSection: true },
  { title: "الجداول", icon: Table, href: "#" },
  { title: "النماذج", icon: ClipboardList, href: "#" },
  { title: "الملف الشخصي", icon: CircleUserRound, href: "#" },

  // Apps Section
  { label: "التطبيقات", isSection: true },
  { title: "الملاحظات", icon: Notebook, href: "#" },
  { title: "التذاكر", icon: Ticket, href: "#" },
  {
    title: "المدونات",
    icon: Languages,
    children: [
      { title: "منشور المدونة", href: "#" },
      { title: "تفاصيل المدونة", href: "#" },
      { title: "تعديل المدونة", href: "#" },
      { title: "إنشاء مدونة", href: "#" },
      { title: "إدارة المدونات", href: "#" },
    ],
  },

  // Form Elements Section
  { label: "عناصر النماذج", isSection: true },
  {
    title: "نماذج Shadcn",
    icon: NotepadText,
    children: [
      { title: "زر", href: "#" },
      { title: "حقل الإدخال", href: "#" },
      { title: "القائمة المنسدلة", href: "#" },
      { title: "خانة الاختيار", href: "#" },
      { title: "زر الاختيار", href: "#" },
    ],
  },
  {
    title: "تخطيطات النماذج",
    icon: AlignStartVertical,
    children: [
      { title: "نماذج أفقية", href: "#" },
      { title: "نماذج عمودية", href: "#" },
      { title: "التحقق من النماذج", href: "#" },
      { title: "أمثلة النماذج", href: "#" },
      { title: "معالج النماذج", href: "#" },
    ],
  },
];

const navItems = [
  {
    title: "مركز المساعدة",
    url: "/theme-pages/faq",
    icon: LifeBuoy,
  },
  {
    title: "التوثيق",
    url: "#",
    icon: BookOpen,
  },
]

export function AppSidebar() {
  return (
    <Sidebar
      side="right"
      dir="rtl"
      className="px-0 h-full **:data-[slot=sidebar-inner]:h-full **:data-[slot=sidebar-inner]:bg-background"
    >
      <div className="flex flex-col gap-2">
        {/* ---------------- Header ---------------- */}
        <SidebarHeader className="px-4 py-4">
          <SidebarMenu>
            <SidebarMenuItem>
              <a href="#" className="w-full h-full">
                <img
                  src="https://images.shadcnspace.com/assets/shadcn-dashboard/logo/fulldark-logo.svg"
                  alt="fulldark-logo"
                  width={100}
                  height={32}
                  className="block dark:hidden"
                />
                <img
                  src="https://images.shadcnspace.com/assets/shadcn-dashboard/logo/fullwhite-logo.svg"
                  alt="fulldark-logo"
                  width={100}
                  height={32}
                  className="hidden dark:block"
                />
              </a>
            </SidebarMenuItem>
          </SidebarMenu>
        </SidebarHeader>

        {/* ---------------- Content ---------------- */}
        <SidebarContent className="overflow-hidden">
          <ScrollArea className="h-[calc(100vh-100px)]">
            <div className="px-4">
              <NavMain items={navData} />
            </div>
            {/* card */}
            <div className="pt-5 px-4">
              <div className="-mx-4 border-t border-b border-border px-5 py-5">
                <div className="flex flex-col gap-5">
                  {/* Plan info */}
                  <div className="flex flex-col gap-2">
                    <div className="flex flex-col gap-4">
                      {/* Header row */}
                      <div className="flex items-center justify-between">
                        <div className="flex items-center gap-2">
                          <Rocket className="size-5 shrink-0" />
                          <span className="font-medium text-base leading-6 text-foreground">الخطة الأساسية</span>
                        </div>
                        <span className="font-medium text-base leading-6 text-foreground">70%</span>
                      </div>
                      {/* Progress bar */}
                      <div className="w-full h-1.5 rounded-full bg-foreground/10 overflow-hidden">
                        <div className="h-full w-[70%] bg-foreground rounded-full" />
                      </div>
                    </div>
                    {/* Usage text */}
                    <p className="text-sm font-normal leading-5 text-muted-foreground text-center">
                      68/100 من الحد الشهري المستخدم
                    </p>
                  </div>
                  {/* Upgrade button */}
                  <Button className="w-full cursor-pointer h-9 bg-foreground text-background hover:bg-foreground/90 rounded-lg text-sm font-medium">
                    الترقية
                  </Button>
                </div>
              </div>
              <SidebarGroup className="mt-auto pt-4">
                <SidebarGroupContent>
                  <SidebarMenu className=" ">
                    {navItems.map((item) => (
                      <SidebarMenuItem key={item.title}>
                        <SidebarMenuButton size="lg" className="h-full cursor-pointer">
                          <a href={item.url}>
                            <div className="flex items-center gap-3 w-full">
                              <item.icon className="shadow-none size-5 shrink-0" />
                              <div className="flex flex-col flex-1 text-left text-sm leading-tight hide-menu whitespace-nowrap">
                                <span className="truncate font-medium">{item.title}</span>
                              </div>
                            </div>
                          </a>
                        </SidebarMenuButton>
                      </SidebarMenuItem>
                    ))}
                  </SidebarMenu>
                </SidebarGroupContent>
              </SidebarGroup>
            </div>
          </ScrollArea>
        </SidebarContent>
      </div>
    </Sidebar>
  );
}
```

### `src/components/shadcn-dashboard/blocks/dashboard-layout/dashboard-layout-02/nav-main.tsx`

```tsx
"use client";

import * as React from "react";
import { ChevronRight, LucideIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import {
  Collapsible,
  CollapsibleTrigger,
  CollapsibleContent,
} from "@/components/ui/collapsible";
import {
  SidebarGroup,
  SidebarGroupLabel,
  SidebarMenu,
  SidebarMenuButton,
  SidebarMenuItem,
  SidebarMenuSub,
  SidebarMenuSubItem,
  SidebarMenuSubButton,
} from "@/components/ui/sidebar";

export type NavItem = {
  label?: string;
  isSection?: boolean;
  title?: string;
  icon?: LucideIcon;
  href?: string;
  children?: NavItem[];
};

export function NavMain({ items }: { items: NavItem[] }) {
  const [activeParent, setActiveParent] = React.useState<string | null>(
    items.find((i) => !i.isSection)?.title || null
  );
  const [activeChild, setActiveChild] = React.useState<string | null>(null);

  return (
    <>
      {items.map((item, index) => (
        <NavMainItem
          key={item.title || item.label || index}
          item={item}
          activeParent={activeParent}
          setActiveParent={setActiveParent}
          activeChild={activeChild}
          setActiveChild={setActiveChild}
        />
      ))}
    </>
  );
}

function NavMainItem({
  item,
  activeParent,
  setActiveParent,
  activeChild,
  setActiveChild,
}: {
  item: NavItem;
  activeParent: string | null;
  activeChild: string | null;
  setActiveParent: (val: string) => void;
  setActiveChild: (val: string | null) => void;
}) {
  const hasChildren = !!item.children?.length;
  const isParentActive = activeParent === item.title;
  const [isOpen, setIsOpen] = React.useState(isParentActive);

  // Sync open state when activeParent changes
  React.useEffect(() => {
    if (isParentActive) {
      setIsOpen(true);
    }
  }, [isParentActive]);

  // Section label
  if (item.isSection && item.label) {
    return (
      <SidebarGroup className="p-0 pt-5 first:pt-0">
        <SidebarGroupLabel className="p-0 text-xs font-medium uppercase text-sidebar-foreground">
          {item.label}
        </SidebarGroupLabel>
      </SidebarGroup>
    );
  }

  // Item with children → collapsible
  if (hasChildren && item.title) {
    return (
      <SidebarGroup className="p-0">
        <SidebarMenu>
          <Collapsible open={isOpen} onOpenChange={setIsOpen}>
            <SidebarMenuItem>
              <CollapsibleTrigger
                className="w-full"
                render={
                  <SidebarMenuButton
                    id={`nav-main-trigger-${item.title.toLowerCase().replace(/\s+/g, '-')}`}
                    tooltip={item.title}
                    isActive={isParentActive}
                    onClick={() => setActiveParent(item.title!)}
                    className={cn(
                      "text-sm font-medium px-3 py-2 h-9 transition-colors cursor-pointer justify-between",
                      isParentActive ? "bg-primary! text-primary-foreground!" : ""
                    )}
                  >
                    <span className="flex items-center gap-2">
                      {item.icon && <item.icon size={16} />}
                      <span>{item.title}</span>
                    </span>
                    <ChevronRight
                      className={cn(
                        "transition-transform duration-200",
                        isOpen ? "rotate-90" : "rtl:rotate-180"
                      )}
                    />
                  </SidebarMenuButton>
                }
              />
              <CollapsibleContent>
                <SidebarMenuSub className="me-0 pe-0 ml-5">
                  {item.children!.map((child, index) => (
                    <NavMainSubItem
                      key={child.title || index}
                      item={child}
                      activeParent={activeParent}
                      setActiveParent={setActiveParent}
                      activeChild={activeChild}
                      setActiveChild={setActiveChild}
                      parentTitle={item.title}
                    />
                  ))}
                </SidebarMenuSub>
              </CollapsibleContent>
            </SidebarMenuItem>
          </Collapsible>
        </SidebarMenu>
      </SidebarGroup>
    );
  }

  // Item without children
  if (item.title) {
    return (
      <SidebarGroup className="p-0">
        <SidebarMenu>
          <SidebarMenuItem>
            <SidebarMenuButton
              id={`nav-main-button-${item.title.toLowerCase().replace(/\s+/g, '-')}`}
              tooltip={item.title}
              isActive={isParentActive}
              onClick={() => {
                setActiveParent(item.title!);
                setActiveChild(null);
              }}
              className={cn(
                "text-sm font-medium px-3 py-2 h-9 transition-colors cursor-pointer",
                isParentActive ? "bg-primary! text-primary-foreground!" : ""
              )}
              render={<a href={item.href} />}
            >
              {item.icon && <item.icon />}
              {item.title}
            </SidebarMenuButton>
          </SidebarMenuItem>
        </SidebarMenu>
      </SidebarGroup>
    );
  }

  return null;
}

function NavMainSubItem({
  item,
  activeParent,
  setActiveParent,
  activeChild,
  setActiveChild,
  parentTitle,
}: {
  item: NavItem;
  activeParent: string | null;
  activeChild: string | null;
  setActiveParent: (val: string) => void;
  setActiveChild: (val: string | null) => void;
  parentTitle?: string;
}) {
  const hasChildren = !!item.children?.length;
  const [isOpen, setIsOpen] = React.useState(false);

  if (hasChildren && item.title) {
    return (
      <SidebarMenuSubItem>
        <Collapsible open={isOpen} onOpenChange={setIsOpen}>
          <CollapsibleTrigger
            className="w-full"
            render={
              <SidebarMenuSubButton
                id={`nav-sub-trigger-${item.title.toLowerCase().replace(/\s+/g, '-')}`}
                className="text-sm font-medium px-3 py-2 h-9 justify-between"
              >
                <span className="flex items-center gap-2">
                  {item.icon && <item.icon />}
                  <span>{item.title}</span>
                </span>
                <ChevronRight
                  className={cn(
                    "transition-transform duration-200",
                    isOpen ? "rotate-90" : "rtl:rotate-180"
                  )}
                />
              </SidebarMenuSubButton>
            }
          />
          <CollapsibleContent>
            <SidebarMenuSub className="me-0 pe-0">
              {item.children!.map((child, index) => (
                <NavMainSubItem
                  key={child.title || index}
                  item={child}
                  activeParent={activeParent}
                  setActiveParent={setActiveParent}
                  activeChild={activeChild}
                  setActiveChild={setActiveChild}
                  parentTitle={parentTitle}
                />
              ))}
            </SidebarMenuSub>
          </CollapsibleContent>
        </Collapsible>
      </SidebarMenuSubItem>
    );
  }

  if (item.title) {
    return (
      <SidebarMenuSubItem className="w-full">
        <SidebarMenuSubButton
          id={`nav-sub-button-${item.title.toLowerCase().replace(/\s+/g, '-')}`}
          className={cn(
            "w-full transition-colors",
            activeChild === item.title ? "bg-muted! text-foreground!" : ""
          )}
          isActive={activeChild === item.title}
          onClick={() => {
            setActiveParent(parentTitle || "");
            setActiveChild(item.title!);
          }}
          render={<a href={item.href}>{item.title}</a>}
        />
      </SidebarMenuSubItem>
    );
  }

  return null;
}
```
