Skip to content

Sidebar Rail

Slim round icon rail: circular icon links on a sand column, the active one a sage circle with a leaf-shaped marker; labels appear as soft tooltips on hover/focus; becomes a bottom tab bar on mobile.

organic-soft/layout/sidebar-rail
Open ↗

Source

import type { ReactNode } from "react";
import { BarChart3, FileText, Home, Leaf, Settings, Truck, type LucideIcon } from "lucide-react";
import { cn } from "@/lib/utils";

export interface SidebarRailProps {
  items?: { label: string; href: string; icon: LucideIcon }[];
  activeHref?: string;
  children?: ReactNode;
  className?: string;
}

const DEFAULT_ITEMS = [
  { label: "Overview", href: "#overview", icon: Home },
  { label: "Footprint", href: "#footprint", icon: BarChart3 },
  { label: "Actions", href: "#actions", icon: Leaf },
  { label: "Suppliers", href: "#suppliers", icon: Truck },
  { label: "Reports", href: "#reports", icon: FileText },
];

function GroveMark({ className }: { className?: string }) {
  return (
    <svg aria-hidden viewBox="0 0 32 32" className={cn("size-8 shrink-0", className)}>
      <circle cx="16" cy="16" r="16" fill="var(--da-primary)" />
      <path d="M16 25V13" stroke="var(--da-primary-fg)" strokeWidth="2" strokeLinecap="round" />
      <path d="M16 17c-4 0-6.5-2.6-6.5-6.5 4 0 6.5 2.6 6.5 6.5Z" fill="var(--da-primary-fg)" opacity=".85" />
      <path d="M16 14c3.6 0 6-2.3 6-6-3.6 0-6 2.3-6 6Z" fill="var(--da-primary-fg)" />
    </svg>
  );
}

/** Slim round icon rail: circular icon links on a sand column, the active one a sage circle with a leaf-shaped marker; labels appear as soft tooltips on hover/focus; becomes a bottom tab bar on mobile. */
export function SidebarRail({ items = DEFAULT_ITEMS, activeHref = "#actions", children, className }: SidebarRailProps) {
  return (
    <div className={cn("flex min-h-dvh flex-col bg-da-bg text-da-fg md:flex-row", className)}>
      <nav
        aria-label="Main"
        className="fixed inset-x-0 bottom-0 z-40 flex items-center justify-around bg-da-surface-2 px-2 py-2 md:sticky md:top-0 md:h-dvh md:w-20 md:flex-col md:justify-start md:gap-3 md:py-5"
      >
        <GroveMark className="mb-6 hidden size-10 md:block" />
        {items.map((it) => {
          const on = it.href === activeHref;
          return (
            <a
              key={it.href}
              href={it.href}
              aria-current={on ? "page" : undefined}
              className={cn(
                "group da-focus da-transition relative grid size-12 place-items-center rounded-full",
                on ? "bg-da-primary text-da-primary-fg" : "text-da-muted-fg hover:bg-da-surface hover:text-da-fg",
              )}
            >
              <it.icon aria-hidden className="size-5" />
              <span className="sr-only">{it.label}</span>
              <span
                aria-hidden
                className="pointer-events-none absolute left-full ml-3 hidden rounded-da-pill bg-da-fg px-3 py-1.5 text-sm whitespace-nowrap text-da-bg opacity-0 transition-[opacity,translate] duration-(--da-duration) group-hover:translate-x-0 group-hover:opacity-100 group-focus-visible:opacity-100 md:block md:-translate-x-1"
              >
                {it.label}
              </span>
              {on && <span aria-hidden className="absolute -right-1 bottom-0 size-3 rounded-[60%_0] bg-da-secondary-fg max-md:hidden" />}
            </a>
          );
        })}
        <a
          href="#settings"
          aria-label="Settings"
          className="da-focus grid size-12 place-items-center rounded-full text-da-muted-fg hover:bg-da-surface hover:text-da-fg md:mt-auto"
        >
          <Settings aria-hidden className="size-5" />
        </a>
      </nav>
      <main className="min-w-0 flex-1 pb-20 md:pb-0">{children}</main>
    </div>
  );
}

export default SidebarRail;

modules/organic-soft/layout/sidebar-rail/index.tsx

Props

PropTypeDefaultDescription
items{ label: string; href: string; icon: LucideIcon }[]—Content items (see the exported types).
activeHrefstring—Active Href.
childrenReactNode—Content.
classNamestring—Extra classes on the root.

Other sidebar variants in Organic Soft

Sidebar in other art directions

App Sidebar

App shell with a sticky left sidebar: workspace header, grouped nav with yellow active state and counters, usage meter, user footer. Becomes a top bar + slide-over drawer below lg.

BrutalistSidebar

Icon Rail

Compact 80px icon rail: ink brand square, square icon links with yellow active state, red counters and ink tooltips on hover/focus, settings pinned at the bottom. Server-safe, CSS-only tooltips.

BrutalistSidebar

Sidebar Collapsible

App sidebar that collapses from 256px to a 76px icon column with a stepped width animation; ink active item, labels become sr-only when collapsed, collapse toggle pinned at the bottom.

BrutalistSidebar

Sidebar Dual

Two-level navigation: an ink icon rail switches sections, and a paper second panel lists that section's links with counts and a yellow active link. Second panel hides on very small screens.

BrutalistSidebar

App Sidebar

Floating frosted sidebar inset from the viewport edges: gradient-orb brand, pill nav items with an ink active state and gradient badges, workspace group, gradient promo card and user chip. Becomes a floating pill top bar + glass drawer below lg.

GlassSidebar

Sidebar Adaptive

Adaptive navigation: a full glass sidebar with brand, gradient action button, labelled links and a usage meter on desktop; a floating bottom tab bar with a raised gradient “+” on mobile.

GlassSidebar

Sidebar Channels

Chat-app style double sidebar: a column of gradient workspace squircles plus a glass channel panel with collapsible sections, private/live icons, unread counts and LIVE meeting badges; drawer on mobile.

GlassSidebar

Sidebar Floating

Floating glass icon rail detached from the viewport edges: gradient logo orb, gradient active item, unread badges, glass tooltips on hover/focus, settings and avatar at the bottom; a floating bottom bar on mobile.

GlassSidebar

App Sidebar

Linear-style app shell: 240px translucent sidebar with workspace switcher, search, "New" button with shortcut, grouped 32px nav rows with counters, team list with color squares and settings at the bottom. Slide-in drawer below lg.

MinimalSidebar

Sidebar Inset

Inset app shell: the sidebar sits on the tinted page background while content lives in a raised rounded panel. Workspace header, collapsible nested sections with guide line, support/settings and user card; drawer on mobile.

MinimalSidebar

Sidebar Rail

Sidebar that collapses between a 224px labelled list and a 56px icon rail (⌘B or bottom button) with tooltips on hover/focus and corner badges; icon-only on mobile. Controlled or uncontrolled.

MinimalSidebar

Sidebar Tree

Docs / settings sidebar with a filter box and a nested collapsible tree auto-expanded to the active page (highlighted in indigo); stacks above content on mobile.

MinimalSidebar

App Sidebar

Typographic app sidebar: hairline right border, logo + site switcher, mono group labels, plain text links with right-aligned mono counts; the active link is ink with a signal dot; drawer on mobile.

Mono CleanSidebar

Sidebar Icons

Narrow icon rail (56px) of square hairline cells; the active cell is filled ink; labels appear as mono tooltips to the right on hover/focus; turns into a bottom bar on mobile.

Mono CleanSidebar

Sidebar Ink

Ink sidebar (stays near-black in dark mode): giant numbered text links “01 Overview”, the active one full white with an arrow, a storage meter as a hairline bar at the bottom; drawer on mobile.

Mono CleanSidebar

Sidebar Tree

CMS page tree: nested pages drawn with hairline guide lines and +/− toggles (aria-expanded), mono “Pages” header with an add button; active page ink with signal dot; drawer on mobile.

Mono CleanSidebar

App Sidebar

Classic enterprise app shell: white bordered sidebar with brand, entity switcher, grouped nav (uppercase group labels, count badges, blue active state), settings and user footer; off-canvas drawer on mobile.

Neo CorporateSidebar

Sidebar Collapsible

Sidebar that collapses from 240px to a 64px icon rail with a toggle button (aria-expanded); collapsed items keep tooltips (title) and sr-only labels. Always a rail on small screens.

Neo CorporateSidebar

Sidebar Dual

Two-level navigation: a narrow icon rail of top-level sections (tooltips, aria-pressed) and a secondary panel listing the selected section’s pages; the panel hides below md.

Neo CorporateSidebar

Sidebar Navy

Dark navy sidebar (fg-colored in light mode, surface in dark mode — dark in both): brand, search field, nav with white-tint active state and badges, and a cash-balance card at the bottom; drawer on mobile.

Neo CorporateSidebar

App Sidebar

Friendly app shell: warm sidebar with emoji workspace chip, big periwinkle “New task” pill, search field, nav with peach count bubbles and a colored-dot board list; slide-in drawer on mobile.

Soft FlatSidebar

Sidebar Boards

Board navigator: starred favorites, then collapsible emoji spaces holding emoji boards with count bubbles; active board in a white pill; dashed “New space” button.

Soft FlatSidebar

Sidebar Card

Floating white sidebar card with generous radius on a tinted page: two-dot logo, nav with lavender active pill, butter “tip of the day” card and user row; horizontal nav on mobile.

Soft FlatSidebar

Sidebar Rail

Slim rounded icon rail: round icons whose active item fills with its own pastel color, dark pill tooltips, emoji avatar at the bottom; floating bottom bar on mobile.

Soft FlatSidebar