Clean, modern building blocks. Copy and paste into your apps. Built with Go and templ. Open Source. Free forever.
Registry reference: these templ ports track the current shadcn/ui Base UI blocks. The public shadcn block previews can still show legacy new-york-v4/Radix variants, so their block-level details may differ.
package sidebar01 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider() { @AppSidebar() @sidebar.Inset() { <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4"> @sidebar.Trigger(sidebar.TriggerProps{Class: "-ml-1"}) @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { Build Your Application } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item() { @breadcrumb.Page() { Data Fetching } } } } </header> <div class="flex flex-1 flex-col gap-4 p-4"> <div class="grid auto-rows-min gap-4 md:grid-cols-3"> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> </div> <div class="min-h-screen flex-1 rounded-xl bg-muted/50 md:min-h-min"></div> </div> } }}package sidebar01 import "github.com/axadrn/shadcn-templ/v2/components/sidebar" // This is sample data.type navItem struct { Title string URL string Items []navSubItem} type navSubItem struct { Title string URL string IsActive bool} var versions = []string{"1.0.1", "1.1.0-alpha", "2.0.0-beta1"} var navMain = []navItem{ { Title: "Getting Started", URL: "#", Items: []navSubItem{ {Title: "Installation", URL: "#"}, {Title: "Project Structure", URL: "#"}, }, }, { Title: "Build Your Application", URL: "#", Items: []navSubItem{ {Title: "Routing", URL: "#"}, {Title: "Data Fetching", URL: "#", IsActive: true}, {Title: "Rendering", URL: "#"}, {Title: "Caching", URL: "#"}, {Title: "Styling", URL: "#"}, {Title: "Optimizing", URL: "#"}, {Title: "Configuring", URL: "#"}, {Title: "Testing", URL: "#"}, {Title: "Authentication", URL: "#"}, {Title: "Deploying", URL: "#"}, {Title: "Upgrading", URL: "#"}, {Title: "Examples", URL: "#"}, }, }, { Title: "API Reference", URL: "#", Items: []navSubItem{ {Title: "Components", URL: "#"}, {Title: "File Conventions", URL: "#"}, {Title: "Functions", URL: "#"}, {Title: "next.config.js Options", URL: "#"}, {Title: "CLI", URL: "#"}, {Title: "Edge Runtime", URL: "#"}, }, }, { Title: "Architecture", URL: "#", Items: []navSubItem{ {Title: "Accessibility", URL: "#"}, {Title: "Fast Refresh", URL: "#"}, {Title: "templ Compiler", URL: "#"}, {Title: "Supported Browsers", URL: "#"}, {Title: "Turbopack", URL: "#"}, }, },} templ AppSidebar() { @sidebar.Sidebar() { @sidebar.Header() { @VersionSwitcher(versions, versions[0]) @SearchForm() } @sidebar.Content() { // We create a SidebarGroup for each parent. for _, item := range navMain { @sidebar.Group() { @sidebar.GroupLabel() { { item.Title } } @sidebar.GroupContent() { @sidebar.Menu() { for _, subItem := range item.Items { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: subItem.URL, IsActive: subItem.IsActive, }) { { subItem.Title } } } } } } } } } @sidebar.Rail() }}package sidebar01 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/label" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ SearchForm() { <form> @sidebar.Group(sidebar.GroupProps{Class: "py-0"}) { @sidebar.GroupContent(sidebar.GroupContentProps{Class: "relative"}) { @label.Label(label.Props{For: "search", Class: "sr-only"}) { Search } @sidebar.Input(sidebar.InputProps{ ID: "search", Placeholder: "Search the docs...", Class: "pl-8", }) @icon.Search(icon.Props{Class: "pointer-events-none absolute top-1/2 left-2 size-4 -translate-y-1/2 opacity-50 select-none"}) } } </form>}package sidebar01 import ( "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ VersionSwitcher(versions []string, defaultVersion string) { @sidebar.Menu() { @sidebar.MenuItem() { @dropdownmenu.DropdownMenu() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Class: "data-popup-open:bg-sidebar-accent data-popup-open:text-sidebar-accent-foreground", Attributes: dropdownmenu.Trigger(ctx), }) { <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"> @icon.GalleryVerticalEnd(icon.Props{Class: "size-4"}) </div> <div class="flex flex-col gap-0.5 leading-none"> <span class="font-medium">Documentation</span> <span class="" data-sidebar01-version-label>v{ defaultVersion }</span> </div> @icon.ChevronsUpDown(icon.Props{Class: "ml-auto"}) } @dropdownmenu.Content(dropdownmenu.ContentProps{ Align: dropdownmenu.AlignStart, Attributes: templ.Attributes{"data-sidebar01-version-switcher": ""}, }) { for _, version := range versions { @dropdownmenu.Item(dropdownmenu.ItemProps{ Attributes: templ.Attributes{"data-version": version}, }) { v{ version } @icon.Check(icon.Props{Class: "ml-auto", Attributes: templ.Attributes{"hidden": version != defaultVersion}}) } } } } } } <script nonce={ templ.GetNonce(ctx) }> (() => { // The setSelectedVersion pendant: a picked version updates the // trigger label and moves the check mark. document.addEventListener("click", (e) => { if (!(e.target instanceof Element)) return; const item = e.target.closest("[data-sidebar01-version-switcher] [data-version]"); if (!item) return; const label = document.querySelector("[data-sidebar01-version-label]"); if (label) label.textContent = "v" + item.dataset.version; item.closest("[data-sidebar01-version-switcher]") .querySelectorAll("[data-version]") .forEach((el) => { const check = el.querySelector("svg"); if (check) check.toggleAttribute("hidden", el !== item); }); }); })(); </script>}package sidebar02 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider() { @AppSidebar() @sidebar.Inset() { <header class="sticky top-0 flex h-16 shrink-0 items-center gap-2 border-b bg-background px-4"> @sidebar.Trigger(sidebar.TriggerProps{Class: "-ml-1"}) @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { Build Your Application } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item() { @breadcrumb.Page() { Data Fetching } } } } </header> <div class="flex flex-1 flex-col gap-4 p-4"> for i := 0; i < 24; i++ { <div class="aspect-video h-12 w-full rounded-lg bg-muted/50"></div> } </div> } }}package sidebar02 import ( "github.com/axadrn/shadcn-templ/v2/components/collapsible" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") // This is sample data.type navItem struct { Title string URL string Items []navSubItem} type navSubItem struct { Title string URL string IsActive bool} var versions = []string{"1.0.1", "1.1.0-alpha", "2.0.0-beta1"} var navMain = []navItem{ { Title: "Getting Started", URL: "#", Items: []navSubItem{ {Title: "Installation", URL: "#"}, {Title: "Project Structure", URL: "#"}, }, }, { Title: "Build Your Application", URL: "#", Items: []navSubItem{ {Title: "Routing", URL: "#"}, {Title: "Data Fetching", URL: "#", IsActive: true}, {Title: "Rendering", URL: "#"}, {Title: "Caching", URL: "#"}, {Title: "Styling", URL: "#"}, {Title: "Optimizing", URL: "#"}, {Title: "Configuring", URL: "#"}, {Title: "Testing", URL: "#"}, {Title: "Authentication", URL: "#"}, {Title: "Deploying", URL: "#"}, {Title: "Upgrading", URL: "#"}, {Title: "Examples", URL: "#"}, }, }, { Title: "API Reference", URL: "#", Items: []navSubItem{ {Title: "Components", URL: "#"}, {Title: "File Conventions", URL: "#"}, {Title: "Functions", URL: "#"}, {Title: "next.config.js Options", URL: "#"}, {Title: "CLI", URL: "#"}, {Title: "Edge Runtime", URL: "#"}, }, }, { Title: "Architecture", URL: "#", Items: []navSubItem{ {Title: "Accessibility", URL: "#"}, {Title: "Fast Refresh", URL: "#"}, {Title: "templ Compiler", URL: "#"}, {Title: "Supported Browsers", URL: "#"}, {Title: "Turbopack", URL: "#"}, }, }, { Title: "Community", URL: "#", Items: []navSubItem{ {Title: "Contribution Guide", URL: "#"}, }, },} templ AppSidebar() { @sidebar.Sidebar() { @sidebar.Header() { @VersionSwitcher(versions, versions[0]) @SearchForm() } @sidebar.Content(sidebar.ContentProps{Class: "gap-0"}) { // We create a collapsible SidebarGroup for each parent. for _, item := range navMain { @collapsible.Collapsible(collapsible.Props{ DefaultOpen: true, Class: "group/collapsible", Attributes: templ.Attributes{"title": item.Title}, }) { @sidebar.Group() { @sidebar.GroupLabel(sidebar.GroupLabelProps{ Class: "group/label text-sm text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", Attributes: collapsible.Trigger(ctx), }) { { item.Title } @icon.ChevronRight(icon.Props{Class: "ml-auto transition-transform group-data-open/collapsible:rotate-90"}) } @collapsible.Content() { @sidebar.GroupContent() { @sidebar.Menu() { for _, subItem := range item.Items { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: subItem.URL, IsActive: subItem.IsActive, }) { { subItem.Title } } } } } } } } } } } @sidebar.Rail() }}package sidebar02 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/label" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ SearchForm() { <form> @sidebar.Group(sidebar.GroupProps{Class: "py-0"}) { @sidebar.GroupContent(sidebar.GroupContentProps{Class: "relative"}) { @label.Label(label.Props{For: "search", Class: "sr-only"}) { Search } @sidebar.Input(sidebar.InputProps{ ID: "search", Placeholder: "Search the docs...", Class: "pl-8", }) @icon.Search(icon.Props{Class: "pointer-events-none absolute top-1/2 left-2 size-4 -translate-y-1/2 opacity-50 select-none"}) } } </form>}package sidebar02 import ( "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ VersionSwitcher(versions []string, defaultVersion string) { @sidebar.Menu() { @sidebar.MenuItem() { @dropdownmenu.DropdownMenu() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Class: "data-popup-open:bg-sidebar-accent data-popup-open:text-sidebar-accent-foreground", Attributes: dropdownmenu.Trigger(ctx), }) { <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"> @icon.GalleryVerticalEnd(icon.Props{Class: "size-4"}) </div> <div class="flex flex-col gap-0.5 leading-none"> <span class="font-medium">Documentation</span> <span class="" data-sidebar02-version-label>v{ defaultVersion }</span> </div> @icon.ChevronsUpDown(icon.Props{Class: "ml-auto"}) } @dropdownmenu.Content(dropdownmenu.ContentProps{ Align: dropdownmenu.AlignStart, Attributes: templ.Attributes{"data-sidebar02-version-switcher": ""}, }) { for _, version := range versions { @dropdownmenu.Item(dropdownmenu.ItemProps{ Attributes: templ.Attributes{"data-version": version}, }) { v{ version } @icon.Check(icon.Props{Class: "ml-auto", Attributes: templ.Attributes{"hidden": version != defaultVersion}}) } } } } } } <script nonce={ templ.GetNonce(ctx) }> (() => { // The setSelectedVersion pendant: a picked version updates the // trigger label and moves the check mark. document.addEventListener("click", (e) => { if (!(e.target instanceof Element)) return; const item = e.target.closest("[data-sidebar02-version-switcher] [data-version]"); if (!item) return; const label = document.querySelector("[data-sidebar02-version-label]"); if (label) label.textContent = "v" + item.dataset.version; item.closest("[data-sidebar02-version-switcher]") .querySelectorAll("[data-version]") .forEach((el) => { const check = el.querySelector("svg"); if (check) check.toggleAttribute("hidden", el !== item); }); }); })(); </script>}package sidebar03 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider() { @AppSidebar() @sidebar.Inset() { <header class="flex h-16 shrink-0 items-center gap-2 border-b"> <div class="flex items-center gap-2 px-3"> @sidebar.Trigger() @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { Build Your Application } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item() { @breadcrumb.Page() { Data Fetching } } } } </div> </header> <div class="flex flex-1 flex-col gap-4 p-4"> <div class="grid auto-rows-min gap-4 md:grid-cols-3"> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> </div> <div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min"></div> </div> } }}package sidebar03 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") // This is sample data.type navItem struct { Title string URL string Items []navSubItem} type navSubItem struct { Title string URL string IsActive bool} var navMain = []navItem{ { Title: "Getting Started", URL: "#", Items: []navSubItem{ {Title: "Installation", URL: "#"}, {Title: "Project Structure", URL: "#"}, }, }, { Title: "Build Your Application", URL: "#", Items: []navSubItem{ {Title: "Routing", URL: "#"}, {Title: "Data Fetching", URL: "#", IsActive: true}, {Title: "Rendering", URL: "#"}, {Title: "Caching", URL: "#"}, {Title: "Styling", URL: "#"}, {Title: "Optimizing", URL: "#"}, {Title: "Configuring", URL: "#"}, {Title: "Testing", URL: "#"}, {Title: "Authentication", URL: "#"}, {Title: "Deploying", URL: "#"}, {Title: "Upgrading", URL: "#"}, {Title: "Examples", URL: "#"}, }, }, { Title: "API Reference", URL: "#", Items: []navSubItem{ {Title: "Components", URL: "#"}, {Title: "File Conventions", URL: "#"}, {Title: "Functions", URL: "#"}, {Title: "next.config.js Options", URL: "#"}, {Title: "CLI", URL: "#"}, {Title: "Edge Runtime", URL: "#"}, }, }, { Title: "Architecture", URL: "#", Items: []navSubItem{ {Title: "Accessibility", URL: "#"}, {Title: "Fast Refresh", URL: "#"}, {Title: "templ Compiler", URL: "#"}, {Title: "Supported Browsers", URL: "#"}, {Title: "Turbopack", URL: "#"}, }, }, { Title: "Community", URL: "#", Items: []navSubItem{ {Title: "Contribution Guide", URL: "#"}, }, },} templ AppSidebar() { @sidebar.Sidebar() { @sidebar.Header() { @sidebar.Menu() { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Href: "#", }) { <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"> @icon.GalleryVerticalEnd(icon.Props{Class: "size-4"}) </div> <div class="flex flex-col gap-0.5 leading-none"> <span class="font-medium">Documentation</span> <span class="">v1.0.0</span> </div> } } } } @sidebar.Content() { @sidebar.Group() { @sidebar.Menu() { for _, item := range navMain { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: item.URL, Class: "font-medium", }) { { item.Title } } if len(item.Items) > 0 { @sidebar.MenuSub() { for _, subItem := range item.Items { @sidebar.MenuSubItem() { @sidebar.MenuSubButton(sidebar.MenuSubButtonProps{ Href: subItem.URL, IsActive: subItem.IsActive, }) { { subItem.Title } } } } } } } } } } } @sidebar.Rail() }}package sidebar04 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider(sidebar.ProviderProps{ // The tsx sets style={{ "--sidebar-width": "19rem" }}; the icon width // keeps the provider's default since the style attribute replaces it. Attributes: templ.Attributes{"style": "--sidebar-width: 19rem; --sidebar-width-icon: 3rem;"}, }) { @AppSidebar() @sidebar.Inset() { <header class="flex h-16 shrink-0 items-center gap-2 px-4"> @sidebar.Trigger(sidebar.TriggerProps{Class: "-ml-1"}) @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { Build Your Application } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item() { @breadcrumb.Page() { Data Fetching } } } } </header> <div class="flex flex-1 flex-col gap-4 p-4 pt-0"> <div class="grid auto-rows-min gap-4 md:grid-cols-3"> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> </div> <div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min"></div> </div> } }}package sidebar04 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") // This is sample data.type navItem struct { Title string URL string Items []navSubItem} type navSubItem struct { Title string URL string IsActive bool} var navMain = []navItem{ { Title: "Getting Started", URL: "#", Items: []navSubItem{ {Title: "Installation", URL: "#"}, {Title: "Project Structure", URL: "#"}, }, }, { Title: "Build Your Application", URL: "#", Items: []navSubItem{ {Title: "Routing", URL: "#"}, {Title: "Data Fetching", URL: "#", IsActive: true}, {Title: "Rendering", URL: "#"}, {Title: "Caching", URL: "#"}, {Title: "Styling", URL: "#"}, {Title: "Optimizing", URL: "#"}, {Title: "Configuring", URL: "#"}, {Title: "Testing", URL: "#"}, {Title: "Authentication", URL: "#"}, {Title: "Deploying", URL: "#"}, {Title: "Upgrading", URL: "#"}, {Title: "Examples", URL: "#"}, }, }, { Title: "API Reference", URL: "#", Items: []navSubItem{ {Title: "Components", URL: "#"}, {Title: "File Conventions", URL: "#"}, {Title: "Functions", URL: "#"}, {Title: "next.config.js Options", URL: "#"}, {Title: "CLI", URL: "#"}, {Title: "Edge Runtime", URL: "#"}, }, }, { Title: "Architecture", URL: "#", Items: []navSubItem{ {Title: "Accessibility", URL: "#"}, {Title: "Fast Refresh", URL: "#"}, {Title: "templ Compiler", URL: "#"}, {Title: "Supported Browsers", URL: "#"}, {Title: "Turbopack", URL: "#"}, }, }, { Title: "Community", URL: "#", Items: []navSubItem{ {Title: "Contribution Guide", URL: "#"}, }, },} templ AppSidebar() { @sidebar.Sidebar(sidebar.Props{Variant: sidebar.VariantFloating}) { @sidebar.Header() { @sidebar.Menu() { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Href: "#", }) { <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"> @icon.GalleryVerticalEnd(icon.Props{Class: "size-4"}) </div> <div class="flex flex-col gap-0.5 leading-none"> <span class="font-medium">Documentation</span> <span class="">v1.0.0</span> </div> } } } } @sidebar.Content() { @sidebar.Group() { @sidebar.Menu(sidebar.MenuProps{Class: "gap-2"}) { for _, item := range navMain { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: item.URL, Class: "font-medium", }) { { item.Title } } if len(item.Items) > 0 { @sidebar.MenuSub(sidebar.MenuSubProps{Class: "ml-0 border-l-0 px-1.5"}) { for _, subItem := range item.Items { @sidebar.MenuSubItem() { @sidebar.MenuSubButton(sidebar.MenuSubButtonProps{ Href: subItem.URL, IsActive: subItem.IsActive, }) { { subItem.Title } } } } } } } } } } } }}package sidebar05 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider() { @AppSidebar() @sidebar.Inset() { <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4"> @sidebar.Trigger(sidebar.TriggerProps{Class: "-ml-1"}) @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { Build Your Application } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item() { @breadcrumb.Page() { Data Fetching } } } } </header> <div class="flex flex-1 flex-col gap-4 p-4"> <div class="grid auto-rows-min gap-4 md:grid-cols-3"> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> </div> <div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min"></div> </div> } }}package sidebar05 import ( "github.com/axadrn/shadcn-templ/v2/components/collapsible" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") // This is sample data.type navItem struct { Title string URL string Items []navSubItem} type navSubItem struct { Title string URL string IsActive bool} var data = struct { NavMain []navItem}{ NavMain: []navItem{ { Title: "Getting Started", URL: "#", Items: []navSubItem{ {Title: "Installation", URL: "#"}, {Title: "Project Structure", URL: "#"}, }, }, { Title: "Build Your Application", URL: "#", Items: []navSubItem{ {Title: "Routing", URL: "#"}, {Title: "Data Fetching", URL: "#", IsActive: true}, {Title: "Rendering", URL: "#"}, {Title: "Caching", URL: "#"}, {Title: "Styling", URL: "#"}, {Title: "Optimizing", URL: "#"}, {Title: "Configuring", URL: "#"}, {Title: "Testing", URL: "#"}, {Title: "Authentication", URL: "#"}, {Title: "Deploying", URL: "#"}, {Title: "Upgrading", URL: "#"}, {Title: "Examples", URL: "#"}, }, }, { Title: "API Reference", URL: "#", Items: []navSubItem{ {Title: "Components", URL: "#"}, {Title: "File Conventions", URL: "#"}, {Title: "Functions", URL: "#"}, {Title: "next.config.js Options", URL: "#"}, {Title: "CLI", URL: "#"}, {Title: "Edge Runtime", URL: "#"}, }, }, { Title: "Architecture", URL: "#", Items: []navSubItem{ {Title: "Accessibility", URL: "#"}, {Title: "Fast Refresh", URL: "#"}, {Title: "templ Compiler", URL: "#"}, {Title: "Supported Browsers", URL: "#"}, {Title: "Turbopack", URL: "#"}, }, }, { Title: "Community", URL: "#", Items: []navSubItem{ {Title: "Contribution Guide", URL: "#"}, }, }, },} templ AppSidebar(props ...sidebar.Props) { @sidebar.Sidebar(props...) { @sidebar.Header() { @sidebar.Menu() { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Size: sidebar.MenuButtonSizeLg, Href: "#"}) { <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"> @icon.GalleryVerticalEnd(icon.Props{Class: "size-4"}) </div> <div class="flex flex-col gap-0.5 leading-none"> <span class="font-medium">Documentation</span> <span class="">v1.0.0</span> </div> } } } @SearchForm() } @sidebar.Content() { @sidebar.Group() { @sidebar.Menu() { for index, item := range data.NavMain { @collapsible.Collapsible(collapsible.Props{ DefaultOpen: index == 1, Class: "group/collapsible", }) { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Attributes: collapsible.Trigger(ctx)}) { { item.Title } @icon.Plus(icon.Props{Class: "ml-auto group-aria-expanded/menu-button:hidden"}) @icon.Minus(icon.Props{Class: "ml-auto hidden group-aria-expanded/menu-button:block"}) } if len(item.Items) > 0 { @collapsible.Content() { @sidebar.MenuSub() { for _, subItem := range item.Items { @sidebar.MenuSubItem() { @sidebar.MenuSubButton(sidebar.MenuSubButtonProps{ Href: subItem.URL, IsActive: subItem.IsActive, }) { { subItem.Title } } } } } } } } } } } } } @sidebar.Rail() }}package sidebar05 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/label" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ SearchForm(attrs ...templ.Attributes) { {{ var a templ.Attributes }} if len(attrs) > 0 { {{ a = attrs[0] }} } <form { a... }> @sidebar.Group(sidebar.GroupProps{Class: "py-0"}) { @sidebar.GroupContent(sidebar.GroupContentProps{Class: "relative"}) { @label.Label(label.Props{For: "search", Class: "sr-only"}) { Search } @sidebar.Input(sidebar.InputProps{ ID: "search", Placeholder: "Search the docs...", Class: "pl-8", }) @icon.Search(icon.Props{Class: "pointer-events-none absolute top-1/2 left-2 size-4 -translate-y-1/2 opacity-50 select-none"}) } } </form>}package sidebar06 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider() { @AppSidebar() @sidebar.Inset() { <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4"> @sidebar.Trigger(sidebar.TriggerProps{Class: "-ml-1"}) @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { Build Your Application } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item() { @breadcrumb.Page() { Data Fetching } } } } </header> <div class="flex flex-1 flex-col gap-4 p-4"> <div class="grid auto-rows-min gap-4 md:grid-cols-3"> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> </div> <div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min"></div> </div> } }}package sidebar06 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") // This is sample data.var data = struct { NavMain []NavMainItem}{ NavMain: []NavMainItem{ { Title: "Getting Started", URL: "#", Items: []NavMainSubItem{ {Title: "Installation", URL: "#"}, {Title: "Project Structure", URL: "#"}, }, }, { Title: "Build Your Application", URL: "#", Items: []NavMainSubItem{ {Title: "Routing", URL: "#"}, {Title: "Data Fetching", URL: "#", IsActive: true}, {Title: "Rendering", URL: "#"}, {Title: "Caching", URL: "#"}, {Title: "Styling", URL: "#"}, {Title: "Optimizing", URL: "#"}, {Title: "Configuring", URL: "#"}, {Title: "Testing", URL: "#"}, {Title: "Authentication", URL: "#"}, {Title: "Deploying", URL: "#"}, {Title: "Upgrading", URL: "#"}, {Title: "Examples", URL: "#"}, }, }, { Title: "API Reference", URL: "#", Items: []NavMainSubItem{ {Title: "Components", URL: "#"}, {Title: "File Conventions", URL: "#"}, {Title: "Functions", URL: "#"}, {Title: "next.config.js Options", URL: "#"}, {Title: "CLI", URL: "#"}, {Title: "Edge Runtime", URL: "#"}, }, }, { Title: "Architecture", URL: "#", Items: []NavMainSubItem{ {Title: "Accessibility", URL: "#"}, {Title: "Fast Refresh", URL: "#"}, {Title: "templ Compiler", URL: "#"}, {Title: "Supported Browsers", URL: "#"}, {Title: "Turbopack", URL: "#"}, }, }, },} templ AppSidebar(props ...sidebar.Props) { @sidebar.Sidebar(props...) { @sidebar.Header() { @sidebar.Menu() { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Size: sidebar.MenuButtonSizeLg, Href: "#"}) { <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"> @icon.GalleryVerticalEnd(icon.Props{Class: "size-4"}) </div> <div class="flex flex-col gap-0.5 leading-none"> <span class="font-medium">Documentation</span> <span class="">v1.0.0</span> </div> } } } } @sidebar.Content() { @NavMain(data.NavMain) } @sidebar.Footer() { <div class="p-1"> @SidebarOptInForm() </div> } @sidebar.Rail() }}package sidebar06 import ( "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type NavMainItem struct { Title string URL string Icon func(...icon.Props) templ.Component IsActive bool Items []NavMainSubItem} type NavMainSubItem struct { Title string URL string IsActive bool} templ NavMain(items []NavMainItem) { @sidebar.Group() { @sidebar.Menu() { for _, item := range items { @dropdownmenu.DropdownMenu() { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Class: "aria-expanded:bg-muted", Attributes: dropdownmenu.Trigger(ctx), }) { { item.Title } @icon.Ellipsis(icon.Props{Class: "ml-auto"}) } if len(item.Items) > 0 { @dropdownmenu.Content(dropdownmenu.ContentProps{ Side: dropdownmenu.SideRight, Align: dropdownmenu.AlignStart, MobileSide: dropdownmenu.SideBottom, MobileAlign: dropdownmenu.AlignEnd, Class: "min-w-56 rounded-lg", }) { for _, subItem := range item.Items { @dropdownmenu.Item(dropdownmenu.ItemProps{Href: subItem.URL}) { { subItem.Title } } } } } } } } } }}package sidebar06 import ( "github.com/axadrn/shadcn-templ/v2/components/button" "github.com/axadrn/shadcn-templ/v2/components/card" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ SidebarOptInForm() { @card.Card(card.Props{Class: "gap-2 py-4 shadow-none"}) { @card.Header(card.HeaderProps{Class: "px-4"}) { @card.Title(card.TitleProps{Class: "text-sm"}) { Subscribe to our newsletter } @card.Description() { Opt-in to receive updates and news about the sidebar. } } @card.Content(card.ContentProps{Class: "px-4"}) { <form> <div class="grid gap-2.5"> @sidebar.Input(sidebar.InputProps{ Placeholder: "Email", Attributes: templ.Attributes{"type": "email"}, }) @button.Button(button.Props{ Class: "w-full bg-sidebar-primary text-sidebar-primary-foreground shadow-none", Size: button.SizeSm, }) { Subscribe } </div> </form> } }}package sidebar07 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider() { @AppSidebar() @sidebar.Inset() { <header class="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12"> <div class="flex items-center gap-2 px-4"> @sidebar.Trigger(sidebar.TriggerProps{Class: "-ml-1"}) @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { Build Your Application } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item() { @breadcrumb.Page() { Data Fetching } } } } </div> </header> <div class="flex flex-1 flex-col gap-4 p-4 pt-0"> <div class="grid auto-rows-min gap-4 md:grid-cols-3"> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> </div> <div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min"></div> </div> } } <script nonce={ templ.GetNonce(ctx) }> (() => { // Keep the selected team details in sync. document.addEventListener("click", (e) => { if (!(e.target instanceof Element)) return; const item = e.target.closest("#sidebar07-team-menu [data-sidebar07-team-index]"); if (!item) return; const i = item.getAttribute("data-sidebar07-team-index"); const name = item.textContent.trim().replace(/⌘\d$/, "").trim(); const plan = ["Enterprise", "Startup", "Free"][parseInt(i, 10)]; document.querySelectorAll("[data-sidebar07-team-logo]").forEach((logo) => { logo.classList.toggle("hidden", logo.getAttribute("data-sidebar07-team-logo") !== i); }); const nameEl = document.querySelector("[data-sidebar07-team-name]"); const planEl = document.querySelector("[data-sidebar07-team-plan]"); if (nameEl) nameEl.textContent = name; if (planEl) planEl.textContent = plan; }); })(); </script>}package sidebar07 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") // This is sample data.var data = struct { User User Teams []Team NavMain []NavMainItem Projects []Project}{ User: User{ Name: "Axel Adrian", Email: "[email protected]", Avatar: "https://github.com/axadrn.png", }, Teams: []Team{ {Name: "Acme Inc", Logo: icon.GalleryVerticalEnd, Plan: "Enterprise"}, {Name: "Acme Corp.", Logo: icon.AudioLines, Plan: "Startup"}, {Name: "Evil Corp.", Logo: icon.Terminal, Plan: "Free"}, }, NavMain: []NavMainItem{ { Title: "Playground", URL: "#", Icon: icon.SquareTerminal, IsActive: true, Items: []NavMainSubItem{ {Title: "History", URL: "#"}, {Title: "Starred", URL: "#"}, {Title: "Settings", URL: "#"}, }, }, { Title: "Models", URL: "#", Icon: icon.Bot, Items: []NavMainSubItem{ {Title: "Genesis", URL: "#"}, {Title: "Explorer", URL: "#"}, {Title: "Quantum", URL: "#"}, }, }, { Title: "Documentation", URL: "#", Icon: icon.BookOpen, Items: []NavMainSubItem{ {Title: "Introduction", URL: "#"}, {Title: "Get Started", URL: "#"}, {Title: "Tutorials", URL: "#"}, {Title: "Changelog", URL: "#"}, }, }, { Title: "Settings", URL: "#", Icon: icon.Settings2, Items: []NavMainSubItem{ {Title: "General", URL: "#"}, {Title: "Team", URL: "#"}, {Title: "Billing", URL: "#"}, {Title: "Limits", URL: "#"}, }, }, }, Projects: []Project{ {Name: "Design Engineering", URL: "#", Icon: icon.Frame}, {Name: "Sales & Marketing", URL: "#", Icon: icon.ChartPie}, {Name: "Travel", URL: "#", Icon: icon.Map}, },} templ AppSidebar(props ...sidebar.Props) { {{ var p sidebar.Props }} if len(props) > 0 { {{ p = props[0] }} } if p.Collapsible == "" { {{ p.Collapsible = sidebar.CollapsibleIcon }} } @sidebar.Sidebar(p) { @sidebar.Header() { @TeamSwitcher(data.Teams) } @sidebar.Content() { @NavMain(data.NavMain) @NavProjects(data.Projects) } @sidebar.Footer() { @NavUser(data.User) } @sidebar.Rail() }}package sidebar07 import ( "github.com/axadrn/shadcn-templ/v2/components/collapsible" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type NavMainItem struct { Title string URL string Icon func(...icon.Props) templ.Component IsActive bool Items []NavMainSubItem} type NavMainSubItem struct { Title string URL string} templ NavMain(items []NavMainItem) { @sidebar.Group() { @sidebar.GroupLabel() { Platform } @sidebar.Menu() { for _, item := range items { @collapsible.Collapsible(collapsible.Props{ DefaultOpen: item.IsActive, Class: "group/collapsible", }) { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Tooltip: item.Title, Attributes: collapsible.Trigger(ctx), }) { if item.Icon != nil { @item.Icon() } <span>{ item.Title }</span> @icon.ChevronRight(icon.Props{Class: "ml-auto transition-transform duration-200 group-data-open/collapsible:rotate-90"}) } @collapsible.Content() { @sidebar.MenuSub() { for _, subItem := range item.Items { @sidebar.MenuSubItem() { @sidebar.MenuSubButton(sidebar.MenuSubButtonProps{Href: subItem.URL}) { <span>{ subItem.Title }</span> } } } } } } } } } }}package sidebar07 import ( "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type Project struct { Name string URL string Icon func(...icon.Props) templ.Component} templ NavProjects(projects []Project) { @sidebar.Group(sidebar.GroupProps{Class: "group-data-[collapsible=icon]:hidden"}) { @sidebar.GroupLabel() { Projects } @sidebar.Menu() { for _, item := range projects { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Href: item.URL}) { @item.Icon() <span>{ item.Name }</span> } @dropdownmenu.DropdownMenu() { @sidebar.MenuAction(sidebar.MenuActionProps{ ShowOnHover: true, Class: "aria-expanded:bg-muted", Attributes: dropdownmenu.Trigger(ctx), }) { @icon.Ellipsis() <span class="sr-only">More</span> } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "w-fit", Side: dropdownmenu.SideRight, Align: dropdownmenu.AlignStart, MobileSide: dropdownmenu.SideBottom, MobileAlign: dropdownmenu.AlignEnd, }) { @dropdownmenu.Item() { @icon.Folder() <span>View Project</span> } @dropdownmenu.Item() { @icon.ArrowRight() <span>Share Project</span> } @dropdownmenu.Separator() @dropdownmenu.Item(dropdownmenu.ItemProps{Variant: dropdownmenu.ItemVariantDestructive}) { @icon.Trash2() <span>Delete Project</span> } } } } } @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Class: "text-sidebar-foreground/70"}) { @icon.Ellipsis(icon.Props{Class: "text-sidebar-foreground/70"}) <span>More</span> } } } }}package sidebar07 import ( "github.com/axadrn/shadcn-templ/v2/components/avatar" "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type User struct { Name string Email string Avatar string} templ NavUser(user User) { @sidebar.Menu() { @sidebar.MenuItem() { @dropdownmenu.DropdownMenu() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Class: "aria-expanded:bg-muted", Attributes: dropdownmenu.Trigger(ctx), }) { @avatar.Avatar() { @avatar.Image(avatar.ImageProps{Src: user.Avatar, Alt: user.Name}) @avatar.Fallback() { AA } } <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">{ user.Name }</span> <span class="truncate text-xs">{ user.Email }</span> </div> @icon.ChevronsUpDown(icon.Props{Class: "ml-auto size-4"}) } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "w-fit", Side: dropdownmenu.SideRight, Align: dropdownmenu.AlignEnd, MobileSide: dropdownmenu.SideBottom, SideOffset: 4, }) { @dropdownmenu.Group() { @dropdownmenu.Label(dropdownmenu.LabelProps{Class: "p-0 font-normal"}) { <div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm"> @avatar.Avatar() { @avatar.Image(avatar.ImageProps{Src: user.Avatar, Alt: user.Name}) @avatar.Fallback() { AA } } <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">{ user.Name }</span> <span class="truncate text-xs">{ user.Email }</span> </div> </div> } } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item() { @icon.Sparkles() Upgrade to Pro } } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item() { @icon.BadgeCheck() Account } @dropdownmenu.Item() { @icon.CreditCard() Billing } @dropdownmenu.Item() { @icon.Bell() Notifications } } @dropdownmenu.Separator() @dropdownmenu.Item() { @icon.LogOut() Log out } } } } }}package sidebar07 import ( "strconv" "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type Team struct { Name string Logo func(...icon.Props) templ.Component Plan string} func teamLogoHidden(i int) string { if i == 0 { return "" } return " hidden"} templ TeamSwitcher(teams []Team) { if len(teams) > 0 { @sidebar.Menu() { @sidebar.MenuItem() { @dropdownmenu.DropdownMenu(dropdownmenu.Props{ID: "sidebar07-team-menu"}) { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Class: "data-popup-open:bg-sidebar-accent data-popup-open:text-sidebar-accent-foreground", Attributes: dropdownmenu.Trigger(ctx), }) { <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"> // Render every logo up front; the page script shows the active one. for i, team := range teams { @team.Logo(icon.Props{ Class: teamLogoHidden(i), Attributes: templ.Attributes{"data-sidebar07-team-logo": strconv.Itoa(i)}, }) } </div> <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium" data-sidebar07-team-name>{ teams[0].Name }</span> <span class="truncate text-xs" data-sidebar07-team-plan>{ teams[0].Plan }</span> </div> @icon.ChevronsUpDown(icon.Props{Class: "ml-auto"}) } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "w-fit", Align: dropdownmenu.AlignStart, Side: dropdownmenu.SideRight, MobileSide: dropdownmenu.SideBottom, SideOffset: 4, }) { @dropdownmenu.Group() { @dropdownmenu.Label(dropdownmenu.LabelProps{Class: "text-xs text-muted-foreground"}) { Teams } for i, team := range teams { @dropdownmenu.Item(dropdownmenu.ItemProps{ Class: "gap-2 p-2", Attributes: templ.Attributes{"data-sidebar07-team-index": strconv.Itoa(i)}, }) { <div class="flex size-6 items-center justify-center rounded-md border"> @team.Logo() </div> { team.Name } @dropdownmenu.Shortcut() { ⌘{ strconv.Itoa(i + 1) } } } } } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item(dropdownmenu.ItemProps{Class: "gap-2 p-2"}) { <div class="flex size-6 items-center justify-center rounded-md border bg-transparent"> @icon.Plus(icon.Props{Class: "size-4"}) </div> <div class="font-medium text-muted-foreground">Add team</div> } } } } } } }}package sidebar08 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider() { @AppSidebar() @sidebar.Inset() { <header class="flex h-16 shrink-0 items-center gap-2"> <div class="flex items-center gap-2 px-4"> @sidebar.Trigger(sidebar.TriggerProps{Class: "-ml-1"}) @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { Build Your Application } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item() { @breadcrumb.Page() { Data Fetching } } } } </div> </header> <div class="flex flex-1 flex-col gap-4 p-4 pt-0"> <div class="grid auto-rows-min gap-4 md:grid-cols-3"> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> </div> <div class="min-h-screen flex-1 rounded-xl bg-muted/50 md:min-h-min"></div> </div> } }}package sidebar08 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") var data = struct { User User NavMain []NavMainItem NavSecondary []NavSecondaryItem Projects []Project}{ User: User{ Name: "Axel Adrian", Email: "[email protected]", Avatar: "https://github.com/axadrn.png", }, NavMain: []NavMainItem{ { Title: "Playground", URL: "#", Icon: icon.SquareTerminal, IsActive: true, Items: []NavMainSubItem{ {Title: "History", URL: "#"}, {Title: "Starred", URL: "#"}, {Title: "Settings", URL: "#"}, }, }, { Title: "Models", URL: "#", Icon: icon.Bot, Items: []NavMainSubItem{ {Title: "Genesis", URL: "#"}, {Title: "Explorer", URL: "#"}, {Title: "Quantum", URL: "#"}, }, }, { Title: "Documentation", URL: "#", Icon: icon.BookOpen, Items: []NavMainSubItem{ {Title: "Introduction", URL: "#"}, {Title: "Get Started", URL: "#"}, {Title: "Tutorials", URL: "#"}, {Title: "Changelog", URL: "#"}, }, }, { Title: "Settings", URL: "#", Icon: icon.Settings2, Items: []NavMainSubItem{ {Title: "General", URL: "#"}, {Title: "Team", URL: "#"}, {Title: "Billing", URL: "#"}, {Title: "Limits", URL: "#"}, }, }, }, NavSecondary: []NavSecondaryItem{ {Title: "Support", URL: "#", Icon: icon.LifeBuoy}, {Title: "Feedback", URL: "#", Icon: icon.Send}, }, Projects: []Project{ {Name: "Design Engineering", URL: "#", Icon: icon.Frame}, {Name: "Sales & Marketing", URL: "#", Icon: icon.ChartPie}, {Name: "Travel", URL: "#", Icon: icon.Map}, },} templ AppSidebar(props ...sidebar.Props) { {{ var p sidebar.Props }} if len(props) > 0 { {{ p = props[0] }} } if p.Variant == "" { {{ p.Variant = sidebar.VariantInset }} } @sidebar.Sidebar(p) { @sidebar.Header() { @sidebar.Menu() { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Size: sidebar.MenuButtonSizeLg, Href: "#"}) { <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"> @icon.Terminal(icon.Props{Class: "size-4"}) </div> <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">Acme Inc</span> <span class="truncate text-xs">Enterprise</span> </div> } } } } @sidebar.Content() { @NavMain(data.NavMain) @NavProjects(data.Projects) @NavSecondary(data.NavSecondary, sidebar.GroupProps{Class: "mt-auto"}) } @sidebar.Footer() { @NavUser(data.User) } }}package sidebar08 import ( "github.com/axadrn/shadcn-templ/v2/components/collapsible" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type NavMainItem struct { Title string URL string Icon func(...icon.Props) templ.Component IsActive bool Items []NavMainSubItem} type NavMainSubItem struct { Title string URL string} templ NavMain(items []NavMainItem) { @sidebar.Group() { @sidebar.GroupLabel() { Platform } @sidebar.Menu() { for _, item := range items { @collapsible.Collapsible(collapsible.Props{DefaultOpen: item.IsActive}) { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: item.URL, Tooltip: item.Title, }) { @item.Icon() <span>{ item.Title }</span> } if len(item.Items) > 0 { @sidebar.MenuAction(sidebar.MenuActionProps{ Class: "aria-expanded:rotate-90", Attributes: collapsible.Trigger(ctx), }) { @icon.ChevronRight() <span class="sr-only">Toggle</span> } @collapsible.Content() { @sidebar.MenuSub() { for _, subItem := range item.Items { @sidebar.MenuSubItem() { @sidebar.MenuSubButton(sidebar.MenuSubButtonProps{Href: subItem.URL}) { <span>{ subItem.Title }</span> } } } } } } } } } } }}package sidebar08 import ( "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type Project struct { Name string URL string Icon func(...icon.Props) templ.Component} templ NavProjects(projects []Project) { @sidebar.Group(sidebar.GroupProps{Class: "group-data-[collapsible=icon]:hidden"}) { @sidebar.GroupLabel() { Projects } @sidebar.Menu() { for _, item := range projects { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Href: item.URL}) { @item.Icon() <span>{ item.Name }</span> } @dropdownmenu.DropdownMenu() { @sidebar.MenuAction(sidebar.MenuActionProps{ ShowOnHover: true, Class: "aria-expanded:bg-muted", Attributes: dropdownmenu.Trigger(ctx), }) { @icon.Ellipsis() <span class="sr-only">More</span> } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "w-48", Side: dropdownmenu.SideRight, Align: dropdownmenu.AlignStart, MobileSide: dropdownmenu.SideBottom, MobileAlign: dropdownmenu.AlignEnd, }) { @dropdownmenu.Item() { @icon.Folder(icon.Props{Class: "text-muted-foreground"}) <span>View Project</span> } @dropdownmenu.Item() { @icon.Share(icon.Props{Class: "text-muted-foreground"}) <span>Share Project</span> } @dropdownmenu.Separator() @dropdownmenu.Item() { @icon.Trash2(icon.Props{Class: "text-muted-foreground"}) <span>Delete Project</span> } } } } } @sidebar.MenuItem() { @sidebar.MenuButton() { @icon.Ellipsis() <span>More</span> } } } }}package sidebar08 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type NavSecondaryItem struct { Title string URL string Icon func(...icon.Props) templ.Component} templ NavSecondary(items []NavSecondaryItem, props ...sidebar.GroupProps) { @sidebar.Group(props...) { @sidebar.GroupContent() { @sidebar.Menu() { for _, item := range items { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: item.URL, Size: sidebar.MenuButtonSizeSm, }) { @item.Icon() <span>{ item.Title }</span> } } } } } }}package sidebar08 import ( "github.com/axadrn/shadcn-templ/v2/components/avatar" "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type User struct { Name string Email string Avatar string} templ NavUser(user User) { @sidebar.Menu() { @sidebar.MenuItem() { @dropdownmenu.DropdownMenu() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Class: "aria-expanded:bg-muted", Attributes: dropdownmenu.Trigger(ctx), }) { @avatar.Avatar() { @avatar.Image(avatar.ImageProps{Src: user.Avatar, Alt: user.Name}) @avatar.Fallback() { AA } } <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">{ user.Name }</span> <span class="truncate text-xs">{ user.Email }</span> </div> @icon.ChevronsUpDown(icon.Props{Class: "ml-auto size-4"}) } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "min-w-56 rounded-lg", Side: dropdownmenu.SideRight, Align: dropdownmenu.AlignEnd, MobileSide: dropdownmenu.SideBottom, SideOffset: 4, }) { @dropdownmenu.Group() { @dropdownmenu.Label(dropdownmenu.LabelProps{Class: "p-0 font-normal"}) { <div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm"> @avatar.Avatar() { @avatar.Image(avatar.ImageProps{Src: user.Avatar, Alt: user.Name}) @avatar.Fallback() { AA } } <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">{ user.Name }</span> <span class="truncate text-xs">{ user.Email }</span> </div> </div> } } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item() { @icon.Sparkles() Upgrade to Pro } } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item() { @icon.BadgeCheck() Account } @dropdownmenu.Item() { @icon.CreditCard() Billing } @dropdownmenu.Item() { @icon.Bell() Notifications } } @dropdownmenu.Separator() @dropdownmenu.Item() { @icon.LogOut() Log out } } } } }}package sidebar09 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider(sidebar.ProviderProps{ // Set both custom widths because this style replaces the provider default. Attributes: templ.Attributes{"style": "--sidebar-width: 350px; --sidebar-width-icon: 3rem;"}, }) { @AppSidebar() @sidebar.Inset() { <header class="sticky top-0 flex shrink-0 items-center gap-2 border-b bg-background p-4"> @sidebar.Trigger(sidebar.TriggerProps{Class: "-ml-1"}) @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { All Inboxes } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item() { @breadcrumb.Page() { Inbox } } } } </header> <div class="flex flex-1 flex-col gap-4 p-4"> for i := 0; i < 24; i++ { <div class="aspect-video h-12 w-full rounded-lg bg-muted/50"></div> } </div> } } <script nonce={ templ.GetNonce(ctx) }> (() => { // The activeItem/setMails/setOpen pendant: a picked inbox item // activates itself, retitles the mail sidebar, reshuffles the // mail list to a random 5-10 slice and expands the sidebar. document.addEventListener("click", (e) => { if (!(e.target instanceof Element)) return; const btn = e.target.closest("[data-sidebar09-nav]"); if (!btn) return; document.querySelectorAll("[data-sidebar09-nav]").forEach((el) => { el.toggleAttribute("data-active", el === btn); }); const title = document.querySelector("[data-sidebar09-active-title]"); if (title) title.textContent = btn.getAttribute("data-sidebar09-nav"); const list = document.querySelector("[data-sidebar09-mails]"); if (list) { const items = [...list.children]; items.sort(() => Math.random() - 0.5); const count = Math.max(5, Math.floor(Math.random() * 10) + 1); items.forEach((item, i) => { list.appendChild(item); item.hidden = i >= count; }); } window.tui.sidebar.setOpen(true, "sidebar09-icon-sidebar"); }); })(); </script>}package sidebar09 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/label" "github.com/axadrn/shadcn-templ/v2/components/sidebar" switchcomp "github.com/axadrn/shadcn-templ/v2/components/switch" "github.com/axadrn/shadcn-templ/v2/utils") // This is sample datatype navItem struct { Title string URL string Icon func(...icon.Props) templ.Component IsActive bool} type mail struct { Name string Email string Subject string Date string Teaser string} var user = User{ Name: "Axel Adrian", Email: "[email protected]", Avatar: "https://github.com/axadrn.png",} var navMain = []navItem{ {Title: "Inbox", URL: "#", Icon: icon.Inbox, IsActive: true}, {Title: "Drafts", URL: "#", Icon: icon.File, IsActive: false}, {Title: "Sent", URL: "#", Icon: icon.Send, IsActive: false}, {Title: "Junk", URL: "#", Icon: icon.ArchiveX, IsActive: false}, {Title: "Trash", URL: "#", Icon: icon.Trash2, IsActive: false},} var mails = []mail{ { Name: "William Smith", Email: "[email protected]", Subject: "Meeting Tomorrow", Date: "09:34 AM", Teaser: "Hi team, just a reminder about our meeting tomorrow at 10 AM.\nPlease come prepared with your project updates.", }, { Name: "Alice Smith", Email: "[email protected]", Subject: "Re: Project Update", Date: "Yesterday", Teaser: "Thanks for the update. The progress looks great so far.\nLet's schedule a call to discuss the next steps.", }, { Name: "Bob Johnson", Email: "[email protected]", Subject: "Weekend Plans", Date: "2 days ago", Teaser: "Hey everyone! I'm thinking of organizing a team outing this weekend.\nWould you be interested in a hiking trip or a beach day?", }, { Name: "Emily Davis", Email: "[email protected]", Subject: "Re: Question about Budget", Date: "2 days ago", Teaser: "I've reviewed the budget numbers you sent over.\nCan we set up a quick call to discuss some potential adjustments?", }, { Name: "Michael Wilson", Email: "[email protected]", Subject: "Important Announcement", Date: "1 week ago", Teaser: "Please join us for an all-hands meeting this Friday at 3 PM.\nWe have some exciting news to share about the company's future.", }, { Name: "Sarah Brown", Email: "[email protected]", Subject: "Re: Feedback on Proposal", Date: "1 week ago", Teaser: "Thank you for sending over the proposal. I've reviewed it and have some thoughts.\nCould we schedule a meeting to discuss my feedback in detail?", }, { Name: "David Lee", Email: "[email protected]", Subject: "New Project Idea", Date: "1 week ago", Teaser: "I've been brainstorming and came up with an interesting project concept.\nDo you have time this week to discuss its potential impact and feasibility?", }, { Name: "Olivia Wilson", Email: "[email protected]", Subject: "Vacation Plans", Date: "1 week ago", Teaser: "Just a heads up that I'll be taking a two-week vacation next month.\nI'll make sure all my projects are up to date before I leave.", }, { Name: "James Martin", Email: "[email protected]", Subject: "Re: Conference Registration", Date: "1 week ago", Teaser: "I've completed the registration for the upcoming tech conference.\nLet me know if you need any additional information from my end.", }, { Name: "Sophia White", Email: "[email protected]", Subject: "Team Dinner", Date: "1 week ago", Teaser: "To celebrate our recent project success, I'd like to organize a team dinner.\nAre you available next Friday evening? Please let me know your preferences.", },} templ AppSidebar() { // Note: I'm using state to show active item. // IRL you should use the url/router. @sidebar.Sidebar(sidebar.Props{ Collapsible: sidebar.CollapsibleIcon, // [&_[data-tui-sidebar-content]]:flex-row is shadcn-templ wiring: the // templ sidebar nests the children one wrapper deeper than the tsx, so // the *:data-[sidebar=sidebar]:flex-row alone does not reach them. Class: "overflow-hidden *:data-[sidebar=sidebar]:flex-row [&_[data-tui-sidebar-content]]:flex-row", }) { // This is the first sidebar // We disable collapsible and adjust width to icon. // This will make the sidebar appear as icons. @sidebar.Sidebar(sidebar.Props{ ID: "sidebar09-icon-sidebar", Collapsible: sidebar.CollapsibleNone, Class: "w-[calc(var(--sidebar-width-icon)+1px)]! border-r", }) { @sidebar.Header() { @sidebar.Menu() { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Class: "md:h-8 md:p-0", Href: "#", }) { <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"> @icon.Terminal(icon.Props{Class: "size-4"}) </div> <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">Acme Inc</span> <span class="truncate text-xs">Enterprise</span> </div> } } } } @sidebar.Content() { @sidebar.Group() { @sidebar.GroupContent(sidebar.GroupContentProps{Class: "px-1.5 md:px-0"}) { @sidebar.Menu() { for _, item := range navMain { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Tooltip: item.Title, // tooltip={{ children, hidden: false }} forces the // tooltip in every sidebar state. TooltipHidden: utils.Ptr(false), IsActive: item.IsActive, Class: "px-2.5 md:px-2", Attributes: templ.Attributes{"data-sidebar09-nav": item.Title}, }) { @item.Icon() <span>{ item.Title }</span> } } } } } } } @sidebar.Footer() { @NavUser(user) } } // This is the second sidebar // We disable collapsible and let it fill remaining space @sidebar.Sidebar(sidebar.Props{ ID: "sidebar09-mail-sidebar", Collapsible: sidebar.CollapsibleNone, Class: "hidden flex-1 md:flex", }) { @sidebar.Header(sidebar.HeaderProps{Class: "gap-3.5 border-b p-4"}) { <div class="flex w-full items-center justify-between"> <div class="text-base font-medium text-foreground" data-sidebar09-active-title> { navMain[0].Title } </div> @label.Label(label.Props{Class: "flex items-center gap-2 text-sm"}) { <span>Unreads</span> @switchcomp.Switch(switchcomp.Props{Class: "shadow-none"}) } </div> @sidebar.Input(sidebar.InputProps{Placeholder: "Type to search..."}) } @sidebar.Content() { @sidebar.Group(sidebar.GroupProps{Class: "px-0"}) { @sidebar.GroupContent(sidebar.GroupContentProps{Attributes: templ.Attributes{"data-sidebar09-mails": ""}}) { for _, mail := range mails { <a href="#" class="flex flex-col items-start gap-2 border-b p-4 text-sm leading-tight whitespace-nowrap last:border-b-0 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground" > <div class="flex w-full items-center gap-2"> <span>{ mail.Name }</span> { " " } <span class="ml-auto text-xs">{ mail.Date }</span> </div> <span class="font-medium">{ mail.Subject }</span> <span class="line-clamp-2 w-[260px] text-xs whitespace-break-spaces"> { mail.Teaser } </span> </a> } } } } } }}package sidebar09 import ( "github.com/axadrn/shadcn-templ/v2/components/avatar" "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type User struct { Name string Email string Avatar string} templ NavUser(user User) { @sidebar.Menu() { @sidebar.MenuItem() { @dropdownmenu.DropdownMenu() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Class: "md:h-8 md:p-0 data-popup-open:bg-sidebar-accent data-popup-open:text-sidebar-accent-foreground", Attributes: dropdownmenu.Trigger(ctx), }) { @avatar.Avatar(avatar.Props{Class: "h-8 w-8 rounded-lg"}) { @avatar.Image(avatar.ImageProps{Src: user.Avatar, Alt: user.Name}) @avatar.Fallback(avatar.FallbackProps{Class: "rounded-lg"}) { AA } } <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">{ user.Name }</span> <span class="truncate text-xs">{ user.Email }</span> </div> @icon.ChevronsUpDown(icon.Props{Class: "ml-auto size-4"}) } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "min-w-56 rounded-lg", Side: dropdownmenu.SideRight, Align: dropdownmenu.AlignEnd, MobileSide: dropdownmenu.SideBottom, SideOffset: 4, }) { @dropdownmenu.Label(dropdownmenu.LabelProps{Class: "p-0 font-normal"}) { <div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm"> @avatar.Avatar(avatar.Props{Class: "h-8 w-8 rounded-lg"}) { @avatar.Image(avatar.ImageProps{Src: user.Avatar, Alt: user.Name}) @avatar.Fallback(avatar.FallbackProps{Class: "rounded-lg"}) { AA } } <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">{ user.Name }</span> <span class="truncate text-xs">{ user.Email }</span> </div> </div> } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item() { @icon.Sparkles() Upgrade to Pro } } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item() { @icon.BadgeCheck() Account } @dropdownmenu.Item() { @icon.CreditCard() Billing } @dropdownmenu.Item() { @icon.Bell() Notifications } } @dropdownmenu.Separator() @dropdownmenu.Item() { @icon.LogOut() Log out } } } } }}package sidebar10 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider() { @AppSidebar() @sidebar.Inset() { <header class="flex h-14 shrink-0 items-center gap-2"> <div class="flex flex-1 items-center gap-2 px-3"> @sidebar.Trigger() @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item() { @breadcrumb.Page(breadcrumb.ItemProps{Class: "line-clamp-1"}) { Project Management & Task Tracking } } } } </div> <div class="ml-auto px-3"> @NavActions() </div> </header> <div class="flex flex-1 flex-col gap-4 px-4 py-10"> <div class="mx-auto h-24 w-full max-w-3xl rounded-xl bg-muted/50"></div> <div class="mx-auto h-full w-full max-w-3xl rounded-xl bg-muted/50"></div> </div> } } <script nonce={ templ.GetNonce(ctx) }> (() => { // Keep the selected team details in sync. document.addEventListener("click", (e) => { if (!(e.target instanceof Element)) return; const item = e.target.closest("#sidebar10-team-menu [data-sidebar10-team-index]"); if (!item) return; const i = item.getAttribute("data-sidebar10-team-index"); const name = item.textContent.trim().replace(/⌘\d$/, "").trim(); document.querySelectorAll("[data-sidebar10-team-logo]").forEach((logo) => { logo.classList.toggle("hidden", logo.getAttribute("data-sidebar10-team-logo") !== i); }); const nameEl = document.querySelector("[data-sidebar10-team-name]"); if (nameEl) nameEl.textContent = name; }); })(); </script>}package sidebar10 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar" "github.com/axadrn/shadcn-templ/v2/utils") // This is sample data.type Team struct { Name string Logo func(...icon.Props) templ.Component Plan string} type NavItem struct { Title string URL string Icon func(...icon.Props) templ.Component IsActive bool Badge string} type Favorite struct { Name string URL string Emoji string} type WorkspacePage struct { Name string URL string Emoji string} type Workspace struct { Name string Emoji string Pages []WorkspacePage} var teams = []Team{ {Name: "Acme Inc", Logo: icon.Terminal, Plan: "Enterprise"}, {Name: "Acme Corp.", Logo: icon.AudioLines, Plan: "Startup"}, {Name: "Evil Corp.", Logo: icon.Terminal, Plan: "Free"},} var navMain = []NavItem{ {Title: "Search", URL: "#", Icon: icon.Search}, {Title: "Ask AI", URL: "#", Icon: icon.Sparkles}, {Title: "Home", URL: "#", Icon: icon.House, IsActive: true}, {Title: "Inbox", URL: "#", Icon: icon.Inbox, Badge: "10"},} var navSecondary = []NavItem{ {Title: "Calendar", URL: "#", Icon: icon.Calendar}, {Title: "Settings", URL: "#", Icon: icon.Settings2}, {Title: "Templates", URL: "#", Icon: icon.Blocks}, {Title: "Trash", URL: "#", Icon: icon.Trash2}, {Title: "Help", URL: "#", Icon: icon.MessageCircleQuestionMark},} var favorites = []Favorite{ {Name: "Project Management & Task Tracking", URL: "#", Emoji: "📊"}, {Name: "Family Recipe Collection & Meal Planning", URL: "#", Emoji: "🍳"}, {Name: "Fitness Tracker & Workout Routines", URL: "#", Emoji: "💪"}, {Name: "Book Notes & Reading List", URL: "#", Emoji: "📚"}, {Name: "Sustainable Gardening Tips & Plant Care", URL: "#", Emoji: "🌱"}, {Name: "Language Learning Progress & Resources", URL: "#", Emoji: "🗣️"}, {Name: "Home Renovation Ideas & Budget Tracker", URL: "#", Emoji: "🏠"}, {Name: "Personal Finance & Investment Portfolio", URL: "#", Emoji: "💰"}, {Name: "Movie & TV Show Watchlist with Reviews", URL: "#", Emoji: "🎬"}, {Name: "Daily Habit Tracker & Goal Setting", URL: "#", Emoji: "✅"},} var workspaces = []Workspace{ { Name: "Personal Life Management", Emoji: "🏠", Pages: []WorkspacePage{ {Name: "Daily Journal & Reflection", URL: "#", Emoji: "📔"}, {Name: "Health & Wellness Tracker", URL: "#", Emoji: "🍏"}, {Name: "Personal Growth & Learning Goals", URL: "#", Emoji: "🌟"}, }, }, { Name: "Professional Development", Emoji: "💼", Pages: []WorkspacePage{ {Name: "Career Objectives & Milestones", URL: "#", Emoji: "🎯"}, {Name: "Skill Acquisition & Training Log", URL: "#", Emoji: "🧠"}, {Name: "Networking Contacts & Events", URL: "#", Emoji: "🤝"}, }, }, { Name: "Creative Projects", Emoji: "🎨", Pages: []WorkspacePage{ {Name: "Writing Ideas & Story Outlines", URL: "#", Emoji: "✍️"}, {Name: "Art & Design Portfolio", URL: "#", Emoji: "🖼️"}, {Name: "Music Composition & Practice Log", URL: "#", Emoji: "🎵"}, }, }, { Name: "Home Management", Emoji: "🏡", Pages: []WorkspacePage{ {Name: "Household Budget & Expense Tracking", URL: "#", Emoji: "💰"}, {Name: "Home Maintenance Schedule & Tasks", URL: "#", Emoji: "🔧"}, {Name: "Family Calendar & Event Planning", URL: "#", Emoji: "📅"}, }, }, { Name: "Travel & Adventure", Emoji: "🧳", Pages: []WorkspacePage{ {Name: "Trip Planning & Itineraries", URL: "#", Emoji: "🗺️"}, {Name: "Travel Bucket List & Inspiration", URL: "#", Emoji: "🌎"}, {Name: "Travel Journal & Photo Gallery", URL: "#", Emoji: "📸"}, }, },} templ AppSidebar(props ...sidebar.Props) { {{ p := sidebar.Props{} }} if len(props) > 0 { {{ p = props[0] }} } {{ p.Class = utils.CN("border-r-0", p.Class) }} @sidebar.Sidebar(p) { @sidebar.Header() { @TeamSwitcher(teams) @NavMain(navMain) } @sidebar.Content() { @NavFavorites(favorites) @NavWorkspaces(workspaces) @NavSecondary(navSecondary, "mt-auto") } @sidebar.Rail() }}package sidebar10 import ( "github.com/axadrn/shadcn-templ/v2/components/button" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/popover" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type action struct { Label string Icon func(...icon.Props) templ.Component} var actions = [][]action{ { {Label: "Customize Page", Icon: icon.Settings2}, {Label: "Turn into wiki", Icon: icon.FileText}, }, { {Label: "Copy Link", Icon: icon.Link}, {Label: "Duplicate", Icon: icon.Copy}, {Label: "Move to", Icon: icon.CornerUpRight}, {Label: "Move to Trash", Icon: icon.Trash2}, }, { {Label: "Undo", Icon: icon.CornerUpLeft}, {Label: "View analytics", Icon: icon.ChartLine}, {Label: "Version History", Icon: icon.GalleryVerticalEnd}, {Label: "Show delete pages", Icon: icon.Trash}, {Label: "Notifications", Icon: icon.Bell}, }, { {Label: "Import", Icon: icon.ArrowUp}, {Label: "Export", Icon: icon.ArrowDown}, },} templ NavActions() { <div class="flex items-center gap-2 text-sm"> <div class="hidden font-medium text-muted-foreground md:inline-block"> Edit Oct 08 </div> @button.Button(button.Props{ Variant: button.VariantGhost, Size: button.SizeIcon, Class: "h-7 w-7", }) { @icon.Star() } @popover.Popover(popover.Props{ ID: "sidebar10-actions-popover", DefaultOpen: true, }) { @button.Button(button.Props{ Variant: button.VariantGhost, Size: button.SizeIcon, Class: "h-7 w-7 data-popup-open:bg-accent", Attributes: popover.Trigger(ctx), }) { @icon.Ellipsis() } @popover.Content(popover.ContentProps{ Class: "w-56 overflow-hidden rounded-lg p-0", Align: popover.AlignEnd, }) { @sidebar.Sidebar(sidebar.Props{ ID: "sidebar10-nav-actions", Collapsible: sidebar.CollapsibleNone, Class: "bg-transparent", }) { @sidebar.Content() { for _, group := range actions { @sidebar.Group(sidebar.GroupProps{Class: "border-b last:border-none"}) { @sidebar.GroupContent(sidebar.GroupContentProps{Class: "gap-0"}) { @sidebar.Menu() { for _, item := range group { @sidebar.MenuItem() { @sidebar.MenuButton() { @item.Icon() <span>{ item.Label }</span> } } } } } } } } } } } </div>}package sidebar10 import ( "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ NavFavorites(favorites []Favorite) { @sidebar.Group(sidebar.GroupProps{Class: "group-data-[collapsible=icon]:hidden"}) { @sidebar.GroupLabel() { Favorites } @sidebar.Menu() { for _, item := range favorites { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: item.URL, Attributes: templ.Attributes{"title": item.Name}, }) { <span>{ item.Emoji }</span> <span>{ item.Name }</span> } @dropdownmenu.DropdownMenu() { @sidebar.MenuAction(sidebar.MenuActionProps{ ShowOnHover: true, Class: "aria-expanded:bg-muted", Attributes: dropdownmenu.Trigger(ctx), }) { @icon.Ellipsis() <span class="sr-only">More</span> } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "w-56 rounded-lg", Side: dropdownmenu.SideRight, Align: dropdownmenu.AlignStart, MobileSide: dropdownmenu.SideBottom, MobileAlign: dropdownmenu.AlignEnd, }) { @dropdownmenu.Item() { @icon.StarOff(icon.Props{Class: "text-muted-foreground"}) <span>Remove from Favorites</span> } @dropdownmenu.Separator() @dropdownmenu.Item() { @icon.Link(icon.Props{Class: "text-muted-foreground"}) <span>Copy Link</span> } @dropdownmenu.Item() { @icon.ArrowUpRight(icon.Props{Class: "text-muted-foreground"}) <span>Open in New Tab</span> } @dropdownmenu.Separator() @dropdownmenu.Item() { @icon.Trash2(icon.Props{Class: "text-muted-foreground"}) <span>Delete</span> } } } } } @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Class: "text-sidebar-foreground/70"}) { @icon.Ellipsis() <span>More</span> } } } }}package sidebar10 import "github.com/axadrn/shadcn-templ/v2/components/sidebar" templ NavMain(items []NavItem) { @sidebar.Menu() { for _, item := range items { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: item.URL, IsActive: item.IsActive, }) { @item.Icon() <span>{ item.Title }</span> } } } }}package sidebar10 import "github.com/axadrn/shadcn-templ/v2/components/sidebar" templ NavSecondary(items []NavItem, class string) { @sidebar.Group(sidebar.GroupProps{Class: class}) { @sidebar.GroupContent() { @sidebar.Menu() { for _, item := range items { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Href: item.URL}) { @item.Icon() <span>{ item.Title }</span> } if item.Badge != "" { @sidebar.MenuBadge() { { item.Badge } } } } } } } }}package sidebar10 import ( "github.com/axadrn/shadcn-templ/v2/components/collapsible" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ NavWorkspaces(workspaces []Workspace) { @sidebar.Group() { @sidebar.GroupLabel() { Workspaces } @sidebar.GroupContent() { @sidebar.Menu() { for _, workspace := range workspaces { @collapsible.Collapsible() { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Href: "#"}) { <span>{ workspace.Emoji }</span> <span>{ workspace.Name }</span> } @sidebar.MenuAction(sidebar.MenuActionProps{ Class: "left-2 bg-sidebar-accent text-sidebar-accent-foreground data-popup-open:rotate-90", ShowOnHover: true, Attributes: collapsible.Trigger(ctx), }) { @icon.ChevronRight() } @sidebar.MenuAction(sidebar.MenuActionProps{ShowOnHover: true}) { @icon.Plus() } @collapsible.Content() { @sidebar.MenuSub() { for _, page := range workspace.Pages { @sidebar.MenuSubItem() { @sidebar.MenuSubButton(sidebar.MenuSubButtonProps{Href: "#"}) { <span>{ page.Emoji }</span> <span>{ page.Name }</span> } } } } } } } } @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Class: "text-sidebar-foreground/70"}) { @icon.Ellipsis() <span>More</span> } } } } }}package sidebar10 import ( "strconv" "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ TeamSwitcher(teams []Team) { if len(teams) > 0 { @sidebar.Menu() { @sidebar.MenuItem() { @dropdownmenu.DropdownMenu(dropdownmenu.Props{ID: "sidebar10-team-menu"}) { @sidebar.MenuButton(sidebar.MenuButtonProps{ Class: "w-fit px-1.5", Attributes: dropdownmenu.Trigger(ctx), }) { <div class="flex aspect-square size-5 items-center justify-center rounded-md bg-sidebar-primary text-sidebar-primary-foreground"> // Render every logo up front; the page script shows the active one. for i, team := range teams { @team.Logo(icon.Props{ Class: teamLogoHidden(i), Attributes: templ.Attributes{"data-sidebar10-team-logo": strconv.Itoa(i)}, }) } </div> <span class="truncate font-medium" data-sidebar10-team-name>{ teams[0].Name }</span> @icon.ChevronDown(icon.Props{Class: "opacity-50"}) } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "w-64 rounded-lg", Align: dropdownmenu.AlignStart, Side: dropdownmenu.SideBottom, SideOffset: 4, }) { @dropdownmenu.Label(dropdownmenu.LabelProps{Class: "text-xs text-muted-foreground"}) { Teams } for i, team := range teams { @dropdownmenu.Item(dropdownmenu.ItemProps{ Class: "gap-2 p-2", Attributes: templ.Attributes{"data-sidebar10-team-index": strconv.Itoa(i)}, }) { <div class="flex size-6 items-center justify-center rounded-xs border"> @team.Logo() </div> { team.Name } @dropdownmenu.Shortcut() { ⌘{ strconv.Itoa(i + 1) } } } } @dropdownmenu.Separator() @dropdownmenu.Item(dropdownmenu.ItemProps{Class: "gap-2 p-2"}) { <div class="flex size-6 items-center justify-center rounded-md border bg-background"> @icon.Plus(icon.Props{Class: "size-4"}) </div> <div class="font-medium text-muted-foreground">Add team</div> } } } } } }} // teamLogoHidden hides every logo except the active one, the SSR half of the// page script's team switch.func teamLogoHidden(i int) string { if i == 0 { return "" } return " hidden"}package sidebar11 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider() { @AppSidebar() @sidebar.Inset() { <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4"> @sidebar.Trigger(sidebar.TriggerProps{Class: "-ml-1"}) @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { components } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { ui } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item() { @breadcrumb.Page() { button.templ } } } } </header> <div class="flex flex-1 flex-col gap-4 p-4"> <div class="grid auto-rows-min gap-4 md:grid-cols-3"> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> </div> <div class="min-h-screen flex-1 rounded-xl bg-muted/50 md:min-h-min"></div> </div> } }}package sidebar11 import ( "github.com/axadrn/shadcn-templ/v2/components/collapsible" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") // This is sample data.type change struct { File string State string} var changes = []change{ {File: "README.md", State: "M"}, {File: "api/hello/route.ts", State: "U"}, {File: "app/layout.templ", State: "M"},} // treeData mirrors the tsx's TreeItem = string | TreeItem[] shape: a string is// a file, a slice is a folder whose first element is its name.var treeData = []any{ []any{ "app", []any{ "api", []any{"hello", []any{"route.ts"}}, "page.templ", "layout.templ", []any{"blog", []any{"page.templ"}}, }, }, []any{ "components", []any{"ui", "button.templ", "card.templ"}, "header.templ", "footer.templ", }, []any{"lib", []any{"util.ts"}}, []any{"public", "favicon.ico", "vercel.svg"}, ".eslintrc.json", ".gitignore", "next.config.js", "tailwind.config.js", "package.json", "README.md",} templ AppSidebar(props ...sidebar.Props) { {{ var p sidebar.Props }} if len(props) > 0 { {{ p = props[0] }} } @sidebar.Sidebar(p) { @sidebar.Content() { @sidebar.Group() { @sidebar.GroupLabel() { Changes } @sidebar.GroupContent() { @sidebar.Menu() { for _, item := range changes { @sidebar.MenuItem() { @sidebar.MenuButton() { @icon.File() { item.File } } @sidebar.MenuBadge() { { item.State } } } } } } } @sidebar.Group() { @sidebar.GroupLabel() { Files } @sidebar.GroupContent() { @sidebar.Menu() { for _, item := range treeData { @tree(item) } } } } } @sidebar.Rail() }} // treeParts is the pendant of the tsx's// const [name, ...items] = Array.isArray(item) ? item : [item]func treeParts(item any) (string, []any) { if arr, ok := item.([]any); ok { if len(arr) == 0 { return "", nil } name, _ := arr[0].(string) return name, arr[1:] } name, _ := item.(string) return name, nil} templ tree(item any) { {{ name, items := treeParts(item) }} if len(items) == 0 { @sidebar.MenuButton(sidebar.MenuButtonProps{ IsActive: name == "button.templ", Class: "data-[active=true]:bg-transparent", }) { @icon.File() { name } } } else { @sidebar.MenuItem() { @collapsible.Collapsible(collapsible.Props{ Class: "group/collapsible [&[data-open]>button>svg:first-child]:rotate-90", DefaultOpen: name == "components" || name == "ui", }) { @sidebar.MenuButton(sidebar.MenuButtonProps{ Attributes: collapsible.Trigger(ctx), }) { @icon.ChevronRight(icon.Props{Class: "transition-transform"}) @icon.Folder() { name } } @collapsible.Content() { @sidebar.MenuSub() { for _, subItem := range items { @tree(subItem) } } } } } }}package sidebar12 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider() { @AppSidebar() @sidebar.Inset() { <header class="sticky top-0 flex h-16 shrink-0 items-center gap-2 border-b bg-background px-4"> @sidebar.Trigger(sidebar.TriggerProps{Class: "-ml-1"}) @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item() { @breadcrumb.Page() { October 2024 } } } } </header> <div class="flex flex-1 flex-col gap-4 p-4"> <div class="grid auto-rows-min gap-4 md:grid-cols-5"> for i := 0; i < 20; i++ { <div class="aspect-square rounded-xl bg-muted/50"></div> } </div> </div> } }}package sidebar12 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") // This is sample data.var user = User{ Name: "Axel Adrian", Email: "[email protected]", Avatar: "https://github.com/axadrn.png",} var calendars = []Calendar{ {Name: "My Calendars", Items: []string{"Personal", "Work", "Family"}}, {Name: "Favorites", Items: []string{"Holidays", "Birthdays"}}, {Name: "Other", Items: []string{"Travel", "Reminders", "Deadlines"}},} templ AppSidebar(props ...sidebar.Props) { {{ var p sidebar.Props }} if len(props) > 0 { {{ p = props[0] }} } @sidebar.Sidebar(p) { @sidebar.Header(sidebar.HeaderProps{Class: "h-16 border-b border-sidebar-border"}) { @NavUser(user) } @sidebar.Content() { @DatePicker() @sidebar.Separator(sidebar.SeparatorProps{Class: "mx-0"}) @Calendars(calendars) } @sidebar.Footer() { @sidebar.Menu() { @sidebar.MenuItem() { @sidebar.MenuButton() { @icon.Plus() <span>New Calendar</span> } } } } @sidebar.Rail() }}package sidebar12 import ( "strconv" "github.com/axadrn/shadcn-templ/v2/components/collapsible" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type Calendar struct { Name string Items []string} templ Calendars(calendars []Calendar) { for index, calendar := range calendars { @sidebar.Group() { @collapsible.Collapsible(collapsible.Props{ DefaultOpen: index == 0, Class: "group/collapsible", }) { @sidebar.GroupLabel(sidebar.GroupLabelProps{ Class: "group/label w-full text-sm text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", Attributes: collapsible.Trigger(ctx), }) { { calendar.Name } @icon.ChevronRight(icon.Props{Class: "ml-auto transition-transform group-data-open/collapsible:rotate-90"}) } @collapsible.Content() { @sidebar.GroupContent() { @sidebar.Menu() { for i, item := range calendar.Items { @sidebar.MenuItem() { @sidebar.MenuButton() { <div data-active={ strconv.FormatBool(i < 2) } class="group/calendar-item flex aspect-square size-4 shrink-0 items-center justify-center rounded-sm border border-sidebar-border text-sidebar-primary-foreground data-[active=true]:border-sidebar-primary data-[active=true]:bg-sidebar-primary" > @icon.Check(icon.Props{Class: "hidden size-3 group-data-[active=true]/calendar-item:block"}) </div> { item } } } } } } } } } @sidebar.Separator(sidebar.SeparatorProps{Class: "mx-0"}) }}package sidebar12 import ( "time" "github.com/axadrn/shadcn-templ/v2/components/calendar" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ DatePicker() { {{ now := time.Now() }} {{ selected := time.Date(now.Year(), now.Month(), 12, 0, 0, 0, 0, now.Location()) }} @sidebar.Group(sidebar.GroupProps{Class: "px-0"}) { @sidebar.GroupContent() { @calendar.Calendar(calendar.Props{ Mode: calendar.ModeSingle, Selected: selected, CaptionLayout: calendar.CaptionLayoutDropdown, Class: "bg-transparent [--cell-size:2.1rem]", }) } }}package sidebar12 import ( "github.com/axadrn/shadcn-templ/v2/components/avatar" "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type User struct { Name string Email string Avatar string} templ NavUser(user User) { @sidebar.Menu() { @sidebar.MenuItem() { @dropdownmenu.DropdownMenu() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Class: "aria-expanded:bg-muted", Attributes: dropdownmenu.Trigger(ctx), }) { @avatar.Avatar() { @avatar.Image(avatar.ImageProps{Src: user.Avatar, Alt: user.Name}) @avatar.Fallback() { AA } } <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">{ user.Name }</span> <span class="truncate text-xs">{ user.Email }</span> </div> @icon.ChevronsUpDown(icon.Props{Class: "ml-auto size-4"}) } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "min-w-56 rounded-lg", Side: dropdownmenu.SideRight, Align: dropdownmenu.AlignStart, MobileSide: dropdownmenu.SideBottom, SideOffset: 4, }) { @dropdownmenu.Group() { @dropdownmenu.Label(dropdownmenu.LabelProps{Class: "p-0 font-normal"}) { <div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm"> @avatar.Avatar() { @avatar.Image(avatar.ImageProps{Src: user.Avatar, Alt: user.Name}) @avatar.Fallback() { AA } } <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">{ user.Name }</span> <span class="truncate text-xs">{ user.Email }</span> </div> </div> } } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item() { @icon.Sparkles() Upgrade to Pro } } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item() { @icon.BadgeCheck() Account } @dropdownmenu.Item() { @icon.CreditCard() Billing } @dropdownmenu.Item() { @icon.Bell() Notifications } } @dropdownmenu.Separator() @dropdownmenu.Item() { @icon.LogOut() Log out } } } } }}package sidebar13 templ Page() { <div class="flex h-svh items-center justify-center"> @SettingsDialog() </div>}package sidebar13 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/button" "github.com/axadrn/shadcn-templ/v2/components/dialog" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type navItem struct { Name string Icon func(...icon.Props) templ.Component} var data = struct { Nav []navItem}{ Nav: []navItem{ {Name: "Notifications", Icon: icon.Bell}, {Name: "Navigation", Icon: icon.Menu}, {Name: "Home", Icon: icon.House}, {Name: "Appearance", Icon: icon.Paintbrush}, {Name: "Messages & media", Icon: icon.MessageCircle}, {Name: "Language & region", Icon: icon.Globe}, {Name: "Accessibility", Icon: icon.Keyboard}, {Name: "Mark as read", Icon: icon.Check}, {Name: "Audio & video", Icon: icon.Video}, {Name: "Connected accounts", Icon: icon.Link}, {Name: "Privacy & visibility", Icon: icon.Lock}, {Name: "Advanced", Icon: icon.Settings}, },} templ SettingsDialog() { // Start this demo with the dialog open. @dialog.Dialog(dialog.Props{DefaultOpen: true}) { @button.Button(button.Props{ Size: button.SizeSm, Attributes: dialog.Trigger(ctx), }) { Open Dialog } @dialog.Content(dialog.ContentProps{Class: "overflow-hidden p-0 md:max-h-[500px] md:max-w-[700px] lg:max-w-[800px]"}) { @dialog.Title(dialog.TitleProps{Class: "sr-only"}) { Settings } @dialog.Description(dialog.DescriptionProps{Class: "sr-only"}) { Customize your settings here. } @sidebar.Provider(sidebar.ProviderProps{Class: "items-start"}) { @sidebar.Sidebar(sidebar.Props{Collapsible: sidebar.CollapsibleNone, Class: "hidden md:flex"}) { @sidebar.Content() { @sidebar.Group() { @sidebar.GroupContent() { @sidebar.Menu() { for _, item := range data.Nav { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: "#", IsActive: item.Name == "Messages & media", }) { @item.Icon() <span>{ item.Name }</span> } } } } } } } } <main class="flex h-[480px] flex-1 flex-col overflow-hidden"> <header class="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12"> <div class="flex items-center gap-2 px-4"> @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { Settings } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item() { @breadcrumb.Page() { Messages & media } } } } </div> </header> <div class="flex flex-1 flex-col gap-4 overflow-y-auto p-4 pt-0"> for range 10 { <div class="aspect-video max-w-3xl rounded-xl bg-muted/50"></div> } </div> </main> } } }}package sidebar14 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider() { @sidebar.Inset() { <header class="flex h-16 shrink-0 items-center gap-2 border-b px-4"> @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item(breadcrumb.ItemProps{Class: "hidden md:block"}) { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { Build Your Application } } @breadcrumb.Separator(breadcrumb.SeparatorProps{Class: "hidden md:block"}) @breadcrumb.Item() { @breadcrumb.Page() { Data Fetching } } } } @sidebar.Trigger(sidebar.TriggerProps{Class: "-mr-1 ml-auto rotate-180"}) </header> <div class="flex flex-1 flex-col gap-4 p-4"> <div class="grid auto-rows-min gap-4 md:grid-cols-3"> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> </div> <div class="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min"></div> </div> } @AppSidebar(sidebar.Props{Side: sidebar.SideRight}) }}package sidebar14 import "github.com/axadrn/shadcn-templ/v2/components/sidebar" // This is sample data.type navItem struct { Title string URL string Items []navSubItem} type navSubItem struct { Title string URL string IsActive bool} var data = struct { NavMain []navItem}{ NavMain: []navItem{ { Title: "Getting Started", URL: "#", Items: []navSubItem{ {Title: "Installation", URL: "#"}, {Title: "Project Structure", URL: "#"}, }, }, { Title: "Build Your Application", URL: "#", Items: []navSubItem{ {Title: "Routing", URL: "#"}, {Title: "Data Fetching", URL: "#", IsActive: true}, {Title: "Rendering", URL: "#"}, {Title: "Caching", URL: "#"}, {Title: "Styling", URL: "#"}, {Title: "Optimizing", URL: "#"}, {Title: "Configuring", URL: "#"}, {Title: "Testing", URL: "#"}, {Title: "Authentication", URL: "#"}, {Title: "Deploying", URL: "#"}, {Title: "Upgrading", URL: "#"}, {Title: "Examples", URL: "#"}, }, }, { Title: "API Reference", URL: "#", Items: []navSubItem{ {Title: "Components", URL: "#"}, {Title: "File Conventions", URL: "#"}, {Title: "Functions", URL: "#"}, {Title: "next.config.js Options", URL: "#"}, {Title: "CLI", URL: "#"}, {Title: "Edge Runtime", URL: "#"}, }, }, { Title: "Architecture", URL: "#", Items: []navSubItem{ {Title: "Accessibility", URL: "#"}, {Title: "Fast Refresh", URL: "#"}, {Title: "templ Compiler", URL: "#"}, {Title: "Supported Browsers", URL: "#"}, {Title: "Turbopack", URL: "#"}, }, }, { Title: "Community", URL: "#", Items: []navSubItem{ {Title: "Contribution Guide", URL: "#"}, }, }, },} templ AppSidebar(props ...sidebar.Props) { {{ var p sidebar.Props }} if len(props) > 0 { {{ p = props[0] }} } @sidebar.Sidebar(p) { @sidebar.Content() { @sidebar.Group() { @sidebar.GroupLabel() { Table of Contents } @sidebar.GroupContent() { @sidebar.Menu() { for _, item := range data.NavMain { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Href: item.URL, Class: "font-medium"}) { { item.Title } } if len(item.Items) > 0 { @sidebar.MenuSub() { for _, subItem := range item.Items { @sidebar.MenuSubItem() { @sidebar.MenuSubButton(sidebar.MenuSubButtonProps{ Href: subItem.URL, IsActive: subItem.IsActive, }) { { subItem.Title } } } } } } } } } } } } @sidebar.Rail() }}package sidebar15 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ Page() { @sidebar.Provider() { @SidebarLeft() @sidebar.Inset() { <header class="sticky top-0 flex h-14 shrink-0 items-center gap-2 bg-background"> <div class="flex flex-1 items-center gap-2 px-3"> @sidebar.Trigger() @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb() { @breadcrumb.List() { @breadcrumb.Item() { @breadcrumb.Page(breadcrumb.ItemProps{Class: "line-clamp-1"}) { Project Management & Task Tracking } } } } </div> </header> <div class="flex flex-1 flex-col gap-4 p-4"> <div class="mx-auto h-24 w-full max-w-3xl rounded-xl bg-muted/50"></div> <div class="mx-auto h-[100vh] w-full max-w-3xl rounded-xl bg-muted/50"></div> </div> } @SidebarRight() } <script nonce={ templ.GetNonce(ctx) }> (() => { // Keep the selected team details in sync. document.addEventListener("click", (e) => { if (!(e.target instanceof Element)) return; const item = e.target.closest("#sidebar15-team-menu [data-team-index]"); if (!item) return; const i = item.getAttribute("data-team-index"); const name = item.textContent.trim().replace(/⌘\d$/, "").trim(); document.querySelectorAll("[data-team-logo]").forEach((logo) => { logo.classList.toggle("hidden", logo.getAttribute("data-team-logo") !== i); }); const nameEl = document.querySelector("[data-team-name]"); if (nameEl) nameEl.textContent = name; }); })(); </script>}package sidebar15 import ( "strconv" "github.com/axadrn/shadcn-templ/v2/components/collapsible" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type Calendar struct { Name string Items []string} templ Calendars(calendars []Calendar) { for index, calendar := range calendars { @sidebar.Group() { @collapsible.Collapsible(collapsible.Props{ DefaultOpen: index == 0, Class: "group/collapsible", }) { @sidebar.GroupLabel(sidebar.GroupLabelProps{ Class: "group/label w-full text-sm text-sidebar-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground", Attributes: collapsible.Trigger(ctx), }) { { calendar.Name } @icon.ChevronRight(icon.Props{Class: "ml-auto transition-transform group-data-open/collapsible:rotate-90"}) } @collapsible.Content() { @sidebar.GroupContent() { @sidebar.Menu() { for i, item := range calendar.Items { @sidebar.MenuItem() { @sidebar.MenuButton() { <div data-active={ strconv.FormatBool(i < 2) } class="group/calendar-item flex aspect-square size-4 shrink-0 items-center justify-center rounded-xs border border-sidebar-border text-sidebar-primary-foreground data-[active=true]:border-sidebar-primary data-[active=true]:bg-sidebar-primary" > @icon.Check(icon.Props{Class: "hidden size-3 group-data-[active=true]/calendar-item:block"}) </div> { item } } } } } } } } } @sidebar.Separator(sidebar.SeparatorProps{Class: "mx-0"}) }}package sidebar15 import ( "time" "github.com/axadrn/shadcn-templ/v2/components/calendar" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ DatePicker() { {{ now := time.Now() }} {{ selected := time.Date(now.Year(), now.Month(), 12, 0, 0, 0, 0, now.Location()) }} @sidebar.Group(sidebar.GroupProps{Class: "px-0"}) { @sidebar.GroupContent() { @calendar.Calendar(calendar.Props{ Mode: calendar.ModeSingle, Selected: selected, CaptionLayout: calendar.CaptionLayoutDropdown, Class: "bg-transparent [--cell-size:2.1rem]", }) } }}package sidebar15 import ( "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type Favorite struct { Name string URL string Emoji string} templ NavFavorites(favorites []Favorite) { @sidebar.Group(sidebar.GroupProps{Class: "group-data-[collapsible=icon]:hidden"}) { @sidebar.GroupLabel() { Favorites } @sidebar.Menu() { for _, item := range favorites { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: item.URL, Attributes: templ.Attributes{"title": item.Name}, }) { <span>{ item.Emoji }</span> <span>{ item.Name }</span> } @dropdownmenu.DropdownMenu() { @sidebar.MenuAction(sidebar.MenuActionProps{ ShowOnHover: true, Class: "aria-expanded:bg-muted", Attributes: dropdownmenu.Trigger(ctx), }) { @icon.Ellipsis() <span class="sr-only">More</span> } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "w-56 rounded-lg", Side: dropdownmenu.SideRight, Align: dropdownmenu.AlignStart, MobileSide: dropdownmenu.SideBottom, MobileAlign: dropdownmenu.AlignEnd, }) { @dropdownmenu.Item() { @icon.StarOff(icon.Props{Class: "text-muted-foreground"}) <span>Remove from Favorites</span> } @dropdownmenu.Separator() @dropdownmenu.Item() { @icon.Link(icon.Props{Class: "text-muted-foreground"}) <span>Copy Link</span> } @dropdownmenu.Item() { @icon.ArrowUpRight(icon.Props{Class: "text-muted-foreground"}) <span>Open in New Tab</span> } @dropdownmenu.Separator() @dropdownmenu.Item() { @icon.Trash2(icon.Props{Class: "text-muted-foreground"}) <span>Delete</span> } } } } } @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Class: "text-sidebar-foreground/70"}) { @icon.Ellipsis() <span>More</span> } } } }}package sidebar15 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type NavMainItem struct { Title string URL string Icon func(...icon.Props) templ.Component IsActive bool Badge string} templ NavMain(items []NavMainItem) { @sidebar.Menu() { for _, item := range items { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: item.URL, IsActive: item.IsActive, }) { @item.Icon() <span>{ item.Title }</span> } } } }}package sidebar15 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type NavSecondaryItem struct { Title string URL string Icon func(...icon.Props) templ.Component Badge string} templ NavSecondary(items []NavSecondaryItem, props ...sidebar.GroupProps) { {{ var p sidebar.GroupProps }} if len(props) > 0 { {{ p = props[0] }} } @sidebar.Group(p) { @sidebar.GroupContent() { @sidebar.Menu() { for _, item := range items { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Href: item.URL}) { @item.Icon() <span>{ item.Title }</span> } if item.Badge != "" { @sidebar.MenuBadge() { { item.Badge } } } } } } } }}package sidebar15 import ( "github.com/axadrn/shadcn-templ/v2/components/avatar" "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type User struct { Name string Email string Avatar string} templ NavUser(user User) { @sidebar.Menu() { @sidebar.MenuItem() { @dropdownmenu.DropdownMenu() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Class: "aria-expanded:bg-muted", Attributes: dropdownmenu.Trigger(ctx), }) { @avatar.Avatar() { @avatar.Image(avatar.ImageProps{Src: user.Avatar, Alt: user.Name}) @avatar.Fallback() { AA } } <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">{ user.Name }</span> <span class="truncate text-xs">{ user.Email }</span> </div> @icon.ChevronsUpDown(icon.Props{Class: "ml-auto size-4"}) } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "min-w-56 rounded-lg", Side: dropdownmenu.SideRight, Align: dropdownmenu.AlignStart, MobileSide: dropdownmenu.SideBottom, SideOffset: 4, }) { @dropdownmenu.Group() { @dropdownmenu.Label(dropdownmenu.LabelProps{Class: "p-0 font-normal"}) { <div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm"> @avatar.Avatar() { @avatar.Image(avatar.ImageProps{Src: user.Avatar, Alt: user.Name}) @avatar.Fallback() { AA } } <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">{ user.Name }</span> <span class="truncate text-xs">{ user.Email }</span> </div> </div> } } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item() { @icon.Sparkles() Upgrade to Pro } } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item() { @icon.BadgeCheck() Account } @dropdownmenu.Item() { @icon.CreditCard() Billing } @dropdownmenu.Item() { @icon.Bell() Notifications } } @dropdownmenu.Separator() @dropdownmenu.Item() { @icon.LogOut() Log out } } } } }}package sidebar15 import ( "github.com/axadrn/shadcn-templ/v2/components/collapsible" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type Workspace struct { Name string Emoji string Pages []WorkspacePage} type WorkspacePage struct { Name string URL string Emoji string} templ NavWorkspaces(workspaces []Workspace) { @sidebar.Group() { @sidebar.GroupLabel() { Workspaces } @sidebar.GroupContent() { @sidebar.Menu() { for _, workspace := range workspaces { @collapsible.Collapsible() { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Href: "#"}) { <span>{ workspace.Emoji }</span> <span>{ workspace.Name }</span> } @sidebar.MenuAction(sidebar.MenuActionProps{ Class: "left-2 bg-sidebar-accent text-sidebar-accent-foreground data-popup-open:rotate-90", ShowOnHover: true, Attributes: collapsible.Trigger(ctx), }) { @icon.ChevronRight() } @sidebar.MenuAction(sidebar.MenuActionProps{ShowOnHover: true}) { @icon.Plus() } @collapsible.Content() { @sidebar.MenuSub() { for _, page := range workspace.Pages { @sidebar.MenuSubItem() { @sidebar.MenuSubButton(sidebar.MenuSubButtonProps{Href: "#"}) { <span>{ page.Emoji }</span> <span>{ page.Name }</span> } } } } } } } } @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Class: "text-sidebar-foreground/70"}) { @icon.Ellipsis() <span>More</span> } } } } }}package sidebar15 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") // This is sample data.var sidebarLeftData = struct { Teams []Team NavMain []NavMainItem NavSecondary []NavSecondaryItem Favorites []Favorite Workspaces []Workspace}{ Teams: []Team{ {Name: "Acme Inc", Logo: icon.Terminal, Plan: "Enterprise"}, {Name: "Acme Corp.", Logo: icon.AudioLines, Plan: "Startup"}, {Name: "Evil Corp.", Logo: icon.Terminal, Plan: "Free"}, }, NavMain: []NavMainItem{ {Title: "Search", URL: "#", Icon: icon.Search}, {Title: "Ask AI", URL: "#", Icon: icon.Sparkles}, {Title: "Home", URL: "#", Icon: icon.House, IsActive: true}, {Title: "Inbox", URL: "#", Icon: icon.Inbox, Badge: "10"}, }, NavSecondary: []NavSecondaryItem{ {Title: "Calendar", URL: "#", Icon: icon.Calendar}, {Title: "Settings", URL: "#", Icon: icon.Settings2}, {Title: "Templates", URL: "#", Icon: icon.Blocks}, {Title: "Trash", URL: "#", Icon: icon.Trash2}, {Title: "Help", URL: "#", Icon: icon.MessageCircleQuestionMark}, }, Favorites: []Favorite{ {Name: "Project Management & Task Tracking", URL: "#", Emoji: "📊"}, {Name: "Family Recipe Collection & Meal Planning", URL: "#", Emoji: "🍳"}, {Name: "Fitness Tracker & Workout Routines", URL: "#", Emoji: "💪"}, {Name: "Book Notes & Reading List", URL: "#", Emoji: "📚"}, {Name: "Sustainable Gardening Tips & Plant Care", URL: "#", Emoji: "🌱"}, {Name: "Language Learning Progress & Resources", URL: "#", Emoji: "🗣️"}, {Name: "Home Renovation Ideas & Budget Tracker", URL: "#", Emoji: "🏠"}, {Name: "Personal Finance & Investment Portfolio", URL: "#", Emoji: "💰"}, {Name: "Movie & TV Show Watchlist with Reviews", URL: "#", Emoji: "🎬"}, {Name: "Daily Habit Tracker & Goal Setting", URL: "#", Emoji: "✅"}, }, Workspaces: []Workspace{ { Name: "Personal Life Management", Emoji: "🏠", Pages: []WorkspacePage{ {Name: "Daily Journal & Reflection", URL: "#", Emoji: "📔"}, {Name: "Health & Wellness Tracker", URL: "#", Emoji: "🍏"}, {Name: "Personal Growth & Learning Goals", URL: "#", Emoji: "🌟"}, }, }, { Name: "Professional Development", Emoji: "💼", Pages: []WorkspacePage{ {Name: "Career Objectives & Milestones", URL: "#", Emoji: "🎯"}, {Name: "Skill Acquisition & Training Log", URL: "#", Emoji: "🧠"}, {Name: "Networking Contacts & Events", URL: "#", Emoji: "🤝"}, }, }, { Name: "Creative Projects", Emoji: "🎨", Pages: []WorkspacePage{ {Name: "Writing Ideas & Story Outlines", URL: "#", Emoji: "✍️"}, {Name: "Art & Design Portfolio", URL: "#", Emoji: "🖼️"}, {Name: "Music Composition & Practice Log", URL: "#", Emoji: "🎵"}, }, }, { Name: "Home Management", Emoji: "🏡", Pages: []WorkspacePage{ {Name: "Household Budget & Expense Tracking", URL: "#", Emoji: "💰"}, {Name: "Home Maintenance Schedule & Tasks", URL: "#", Emoji: "🔧"}, {Name: "Family Calendar & Event Planning", URL: "#", Emoji: "📅"}, }, }, { Name: "Travel & Adventure", Emoji: "🧳", Pages: []WorkspacePage{ {Name: "Trip Planning & Itineraries", URL: "#", Emoji: "🗺️"}, {Name: "Travel Bucket List & Inspiration", URL: "#", Emoji: "🌎"}, {Name: "Travel Journal & Photo Gallery", URL: "#", Emoji: "📸"}, }, }, },} templ SidebarLeft(props ...sidebar.Props) { {{ var p sidebar.Props }} if len(props) > 0 { {{ p = props[0] }} } if p.Class == "" { {{ p.Class = "border-r-0" }} } @sidebar.Sidebar(p) { @sidebar.Header() { @TeamSwitcher(sidebarLeftData.Teams) @NavMain(sidebarLeftData.NavMain) } @sidebar.Content() { @NavFavorites(sidebarLeftData.Favorites) @NavWorkspaces(sidebarLeftData.Workspaces) @NavSecondary(sidebarLeftData.NavSecondary, sidebar.GroupProps{Class: "mt-auto"}) } @sidebar.Rail() }}package sidebar15 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") // This is sample data.var sidebarRightData = struct { User User Calendars []Calendar}{ User: User{ Name: "Axel Adrian", Email: "[email protected]", Avatar: "https://github.com/axadrn.png", }, Calendars: []Calendar{ {Name: "My Calendars", Items: []string{"Personal", "Work", "Family"}}, {Name: "Favorites", Items: []string{"Holidays", "Birthdays"}}, {Name: "Other", Items: []string{"Travel", "Reminders", "Deadlines"}}, },} templ SidebarRight(props ...sidebar.Props) { {{ var p sidebar.Props }} if len(props) > 0 { {{ p = props[0] }} } // The explicit ID keeps this sidebar's element id distinct from the // left sidebar, which takes the provider's id for its trigger. if p.ID == "" { {{ p.ID = "sidebar15-right" }} } if p.Collapsible == "" { {{ p.Collapsible = sidebar.CollapsibleNone }} } if p.Class == "" { {{ p.Class = "sticky top-0 hidden h-svh border-l lg:flex" }} } @sidebar.Sidebar(p) { @sidebar.Header(sidebar.HeaderProps{Class: "h-16 border-b border-sidebar-border"}) { @NavUser(sidebarRightData.User) } @sidebar.Content() { @DatePicker() @sidebar.Separator(sidebar.SeparatorProps{Class: "mx-0"}) @Calendars(sidebarRightData.Calendars) } @sidebar.Footer() { @sidebar.Menu() { @sidebar.MenuItem() { @sidebar.MenuButton() { @icon.Plus() <span>New Calendar</span> } } } } }}package sidebar15 import ( "strconv" "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type Team struct { Name string Logo func(...icon.Props) templ.Component Plan string} func teamLogoHidden(i int) string { if i == 0 { return "" } return " hidden"} templ TeamSwitcher(teams []Team) { if len(teams) > 0 { @sidebar.Menu() { @sidebar.MenuItem() { @dropdownmenu.DropdownMenu(dropdownmenu.Props{ID: "sidebar15-team-menu"}) { @sidebar.MenuButton(sidebar.MenuButtonProps{ Class: "w-fit px-1.5 aria-expanded:bg-muted aria-expanded:text-foreground", Attributes: dropdownmenu.Trigger(ctx), }) { <div class="flex aspect-square size-5 items-center justify-center rounded-md bg-sidebar-primary text-sidebar-primary-foreground"> // Render every logo up front; the page script shows the active one. for i, team := range teams { @team.Logo(icon.Props{ Class: teamLogoHidden(i), Attributes: templ.Attributes{"data-team-logo": strconv.Itoa(i)}, }) } </div> <span class="truncate font-medium" data-team-name>{ teams[0].Name }</span> @icon.ChevronDown(icon.Props{Class: "opacity-50"}) } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "w-64 rounded-lg", Align: dropdownmenu.AlignStart, Side: dropdownmenu.SideBottom, SideOffset: 4, }) { @dropdownmenu.Label(dropdownmenu.LabelProps{Class: "text-xs text-muted-foreground"}) { Teams } for i, team := range teams { @dropdownmenu.Item(dropdownmenu.ItemProps{ Class: "gap-2 p-2", Attributes: templ.Attributes{"data-team-index": strconv.Itoa(i)}, }) { <div class="flex size-6 items-center justify-center rounded-xs border"> @team.Logo() </div> { team.Name } @dropdownmenu.Shortcut() { ⌘{ strconv.Itoa(i + 1) } } } } @dropdownmenu.Separator() @dropdownmenu.Item(dropdownmenu.ItemProps{Class: "gap-2 p-2"}) { <div class="flex size-6 items-center justify-center rounded-md border bg-background"> @icon.Plus(icon.Props{Class: "size-4"}) </div> <div class="font-medium text-muted-foreground">Add team</div> } } } } } }}package sidebar16 import "github.com/axadrn/shadcn-templ/v2/components/sidebar" templ Page() { <div class="[--header-height:calc(--spacing(14))]"> @sidebar.Provider(sidebar.ProviderProps{Class: "flex flex-col"}) { @SiteHeader() <div class="flex flex-1"> @AppSidebar() @sidebar.Inset() { <div class="flex flex-1 flex-col gap-4 p-4"> <div class="grid auto-rows-min gap-4 md:grid-cols-3"> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> <div class="aspect-video rounded-xl bg-muted/50"></div> </div> <div class="min-h-screen flex-1 rounded-xl bg-muted/50 md:min-h-min"></div> </div> } </div> } </div>}package sidebar16 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") var data = struct { User User NavMain []NavMainItem NavSecondary []NavSecondaryItem Projects []Project}{ User: User{ Name: "Axel Adrian", Email: "[email protected]", Avatar: "https://github.com/axadrn.png", }, NavMain: []NavMainItem{ { Title: "Playground", URL: "#", Icon: icon.SquareTerminal, IsActive: true, Items: []NavMainSubItem{ {Title: "History", URL: "#"}, {Title: "Starred", URL: "#"}, {Title: "Settings", URL: "#"}, }, }, { Title: "Models", URL: "#", Icon: icon.Bot, Items: []NavMainSubItem{ {Title: "Genesis", URL: "#"}, {Title: "Explorer", URL: "#"}, {Title: "Quantum", URL: "#"}, }, }, { Title: "Documentation", URL: "#", Icon: icon.BookOpen, Items: []NavMainSubItem{ {Title: "Introduction", URL: "#"}, {Title: "Get Started", URL: "#"}, {Title: "Tutorials", URL: "#"}, {Title: "Changelog", URL: "#"}, }, }, { Title: "Settings", URL: "#", Icon: icon.Settings2, Items: []NavMainSubItem{ {Title: "General", URL: "#"}, {Title: "Team", URL: "#"}, {Title: "Billing", URL: "#"}, {Title: "Limits", URL: "#"}, }, }, }, NavSecondary: []NavSecondaryItem{ {Title: "Support", URL: "#", Icon: icon.LifeBuoy}, {Title: "Feedback", URL: "#", Icon: icon.Send}, }, Projects: []Project{ {Name: "Design Engineering", URL: "#", Icon: icon.Frame}, {Name: "Sales & Marketing", URL: "#", Icon: icon.ChartPie}, {Name: "Travel", URL: "#", Icon: icon.Map}, },} templ AppSidebar(props ...sidebar.Props) { {{ var p sidebar.Props }} if len(props) > 0 { {{ p = props[0] }} } if p.Class == "" { {{ p.Class = "top-(--header-height) h-[calc(100svh-var(--header-height))]!" }} } @sidebar.Sidebar(p) { @sidebar.Header() { @sidebar.Menu() { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Href: "#", }) { <div class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"> @icon.Terminal(icon.Props{Class: "size-4"}) </div> <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">Acme Inc</span> <span class="truncate text-xs">Enterprise</span> </div> } } } } @sidebar.Content() { @NavMain(data.NavMain) @NavProjects(data.Projects) @NavSecondary(data.NavSecondary, sidebar.GroupProps{Class: "mt-auto"}) } @sidebar.Footer() { @NavUser(data.User) } }}package sidebar16 import ( "github.com/axadrn/shadcn-templ/v2/components/collapsible" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type NavMainItem struct { Title string URL string Icon func(...icon.Props) templ.Component IsActive bool Items []NavMainSubItem} type NavMainSubItem struct { Title string URL string} templ NavMain(items []NavMainItem) { @sidebar.Group() { @sidebar.GroupLabel() { Platform } @sidebar.Menu() { for _, item := range items { @collapsible.Collapsible(collapsible.Props{DefaultOpen: item.IsActive}) { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: item.URL, Tooltip: item.Title, }) { @item.Icon() <span>{ item.Title }</span> } if len(item.Items) > 0 { @sidebar.MenuAction(sidebar.MenuActionProps{ Class: "aria-expanded:rotate-90", Attributes: collapsible.Trigger(ctx), }) { @icon.ChevronRight() <span class="sr-only">Toggle</span> } @collapsible.Content() { @sidebar.MenuSub() { for _, subItem := range item.Items { @sidebar.MenuSubItem() { @sidebar.MenuSubButton(sidebar.MenuSubButtonProps{Href: subItem.URL}) { <span>{ subItem.Title }</span> } } } } } } } } } } }}package sidebar16 import ( "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type Project struct { Name string URL string Icon func(...icon.Props) templ.Component} templ NavProjects(projects []Project) { @sidebar.Group(sidebar.GroupProps{Class: "group-data-[collapsible=icon]:hidden"}) { @sidebar.GroupLabel() { Projects } @sidebar.Menu() { for _, item := range projects { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{Href: item.URL}) { @item.Icon() <span>{ item.Name }</span> } @dropdownmenu.DropdownMenu() { @sidebar.MenuAction(sidebar.MenuActionProps{ ShowOnHover: true, Class: "aria-expanded:bg-muted", Attributes: dropdownmenu.Trigger(ctx), }) { @icon.Ellipsis() <span class="sr-only">More</span> } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "w-48", Side: dropdownmenu.SideRight, Align: dropdownmenu.AlignStart, MobileSide: dropdownmenu.SideBottom, MobileAlign: dropdownmenu.AlignEnd, }) { @dropdownmenu.Item() { @icon.Folder(icon.Props{Class: "text-muted-foreground"}) <span>View Project</span> } @dropdownmenu.Item() { @icon.Share(icon.Props{Class: "text-muted-foreground"}) <span>Share Project</span> } @dropdownmenu.Separator() @dropdownmenu.Item() { @icon.Trash2(icon.Props{Class: "text-muted-foreground"}) <span>Delete Project</span> } } } } } @sidebar.MenuItem() { @sidebar.MenuButton() { @icon.Ellipsis() <span>More</span> } } } }}package sidebar16 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type NavSecondaryItem struct { Title string URL string Icon func(...icon.Props) templ.Component} templ NavSecondary(items []NavSecondaryItem, props ...sidebar.GroupProps) { {{ var p sidebar.GroupProps }} if len(props) > 0 { {{ p = props[0] }} } @sidebar.Group(p) { @sidebar.GroupContent() { @sidebar.Menu() { for _, item := range items { @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: item.URL, Size: sidebar.MenuButtonSizeSm, }) { @item.Icon() <span>{ item.Title }</span> } } } } } }}package sidebar16 import ( "github.com/axadrn/shadcn-templ/v2/components/avatar" "github.com/axadrn/shadcn-templ/v2/components/dropdownmenu" "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type User struct { Name string Email string Avatar string} templ NavUser(user User) { @sidebar.Menu() { @sidebar.MenuItem() { @dropdownmenu.DropdownMenu() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Size: sidebar.MenuButtonSizeLg, Class: "aria-expanded:bg-muted aria-expanded:text-foreground", Attributes: dropdownmenu.Trigger(ctx), }) { @avatar.Avatar() { @avatar.Image(avatar.ImageProps{Src: user.Avatar, Alt: user.Name}) @avatar.Fallback() { AA } } <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">{ user.Name }</span> <span class="truncate text-xs">{ user.Email }</span> </div> @icon.ChevronsUpDown(icon.Props{Class: "ml-auto size-4"}) } @dropdownmenu.Content(dropdownmenu.ContentProps{ Class: "min-w-56 rounded-lg", Side: dropdownmenu.SideRight, Align: dropdownmenu.AlignEnd, MobileSide: dropdownmenu.SideBottom, SideOffset: 4, }) { @dropdownmenu.Group() { @dropdownmenu.Label(dropdownmenu.LabelProps{Class: "p-0 font-normal"}) { <div class="flex items-center gap-2 px-1 py-1.5 text-left text-sm"> @avatar.Avatar() { @avatar.Image(avatar.ImageProps{Src: user.Avatar, Alt: user.Name}) @avatar.Fallback() { AA } } <div class="grid flex-1 text-left text-sm leading-tight"> <span class="truncate font-medium">{ user.Name }</span> <span class="truncate text-xs">{ user.Email }</span> </div> </div> } } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item() { @icon.Sparkles() Upgrade to Pro } } @dropdownmenu.Separator() @dropdownmenu.Group() { @dropdownmenu.Item() { @icon.BadgeCheck() Account } @dropdownmenu.Item() { @icon.CreditCard() Billing } @dropdownmenu.Item() { @icon.Bell() Notifications } } @dropdownmenu.Separator() @dropdownmenu.Item() { @icon.LogOut() Log out } } } } }}package sidebar16 import ( "github.com/axadrn/shadcn-templ/v2/components/icon" "github.com/axadrn/shadcn-templ/v2/components/label" "github.com/axadrn/shadcn-templ/v2/components/sidebar") type SearchFormProps struct { Class string Attributes templ.Attributes} templ SearchForm(props ...SearchFormProps) { {{ var p SearchFormProps }} if len(props) > 0 { {{ p = props[0] }} } <form if p.Class != "" { class={ p.Class } } { p.Attributes... } > <div class="relative"> @label.Label(label.Props{For: "search", Class: "sr-only"}) { Search } @sidebar.Input(sidebar.InputProps{ ID: "search", Placeholder: "Type to search...", Class: "h-8 pl-7", }) @icon.Search(icon.Props{Class: "pointer-events-none absolute top-1/2 left-2 size-4 -translate-y-1/2 opacity-50 select-none"}) </div> </form>}package sidebar16 import ( "github.com/axadrn/shadcn-templ/v2/components/breadcrumb" "github.com/axadrn/shadcn-templ/v2/components/separator" "github.com/axadrn/shadcn-templ/v2/components/sidebar") templ SiteHeader() { <header class="sticky top-0 z-50 flex w-full items-center border-b bg-background"> <div class="flex h-(--header-height) w-full items-center gap-2 px-4"> // The onClick={toggleSidebar} ghost button with SidebarIcon, the // sidebar trigger renders the same ghost icon button. @sidebar.Trigger(sidebar.TriggerProps{Class: "h-8 w-8"}) @separator.Separator(separator.Props{ Orientation: separator.OrientationVertical, Class: "mr-2 data-vertical:h-4 data-vertical:self-auto", }) @breadcrumb.Breadcrumb(breadcrumb.Props{Class: "hidden sm:block"}) { @breadcrumb.List() { @breadcrumb.Item() { @breadcrumb.Link(breadcrumb.LinkProps{Href: "#"}) { Build Your Application } } @breadcrumb.Separator() @breadcrumb.Item() { @breadcrumb.Page() { Data Fetching } } } } @SearchForm(SearchFormProps{Class: "w-full sm:ml-auto sm:w-auto"}) </div> </header>}