Sidebar
Composable app sidebar that collapses to an icon rail with tooltips, slides an ember active chip between items and opens as a side sheet on mobile.
Preview
Install
Add the editable source with the shadcn CLI. Your project also needs the shared theme tokens this component uses. Setup and requirements. The Pebble installer is not published yet.
npx shadcn@latest add https://pebbleui.com/r/sidebar.jsonProps
| Prop | Type | Default | Description |
|---|---|---|---|
| defaultOpen | boolean | true | SidebarProvider: expanded on first render (uncontrolled). |
| open / onOpenChange | boolean / (open: boolean) => void | — | SidebarProvider: controlled desktop state. |
| shortcut | string | false | "b" | SidebarProvider: Ctrl/Cmd + key toggles the sidebar. false turns it off. |
| collapsible | "icon" | "offcanvas" | "none" | "icon" | Sidebar: collapse to an icon rail, off-canvas, or never. Mobile uses a sheet. |
| label | string | "Sidebar" | Sidebar: accessible name of the navigation landmark. |
| isActive | boolean | false | SidebarMenuButton / SidebarMenuSubButton: draws the sliding chip and sets aria-current. |
| tooltip | string | — | SidebarMenuButton: label shown while collapsed to icons. |
| size | "md" | "lg" | "md" | SidebarMenuButton: lg for workspace switcher and user rows. |
| tone | "default" | "accent" | "default" | SidebarMenuBadge: accent counts stay visible as an ember dot when collapsed. |
Build notes
- **Layout.** Unlike shadcn's fixed-position sidebar with a spacer, ours is an
in-flow flex child, so it works inside a framed mock as well as a full page.
The provider sets `--sidebar-width: 15rem` and `--sidebar-width-icon: 3rem`.
The outer `div` animates `width` (320 ms, `ease-move`) with
`overflow-hidden`; the inner `nav` keeps the full width for off-canvas so it
clips rather than reflows, and narrows to the rail width in icon mode.
- **State through CSS.** The outer element carries `data-state` and
`data-collapsible` (`"icon" | "offcanvas" | ""`) and the named group
`group/sidebar`; every part restyles with
`group-data-[collapsible=icon]/sidebar:*` so no part re-renders on toggle.
- **Labels.** Collapsed menu buttons become `size-8`; every child after the
first non-indicator child (label, chevron) fades to opacity 0 via
`[&>:not([data-slot=sidebar-active-indicator])~*]`, keeping it as the
accessible name. Group labels slide under with `-mt-7` + fade.
- **Active chip.** A `motion.span` with a provider-unique `layoutId` (from
`useId`) rendered inside the active button, `absolute inset-0 -z-10` on an
`isolate` button: card surface, `ring-hairline`, `shadow-raised-xs`,
`inset-shadow-highlight` (muted surface in dark), with a 3 px ember bar on
its left edge. Spring 420/32/0.8. Top-level and sub buttons share the id so
it travels into nested menus.
- **Badge.** Absolute at the right; when collapsed the accent badge becomes a
6 px ember dot at the icon's top-right (`text-[0px]`, `size-1.5`), and plain
counts hide.
- **Surfaces.** The sidebar has no chrome (it sits on `bg-background`); the
inset is the raised card (`m-2 rounded-xl ring-hairline shadow-raised-sm
inset-shadow-highlight`). Hover is a 4.5% foreground tint so it reads in
both themes.
- **Mobile.** `matchMedia("(max-width: 767px)")` in an effect (starts false,
SSR-safe); on mobile `Sidebar` renders inside `SideSheet side="left"`.
- **Tooltips.** `TooltipProvider delayDuration={0}` in the provider;
`TooltipContent hidden` unless collapsed on desktop.
<!-- PEBBLE-LICENSE -->View source
registry/nav/sidebar/sidebar.tsx
"use client";
/* PEBBLE-LICENSE
Built by Pebble. Component: sidebar.
First-party license: MIT
The following first-party terms apply only to original Pebble material.
MIT License
Copyright (c) 2026 Praxys Solutions LLC (Pebble)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
THIRD-PARTY NOTICES
These notices apply to identified upstream portions; Pebble terms do not replace or narrow their rights.
Upstream: https://raw.githubusercontent.com/shadcn-ui/ui/main/LICENSE.md
MIT License
Copyright (c) 2023 shadcn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
END PEBBLE-LICENSE */
import * as React from "react";
import { MotionConfig, motion } from "motion/react";
import { Slot } from "radix-ui";
import { cn } from "@/lib/utils";
import {
SideSheet,
SideSheetContent,
SideSheetDescription,
SideSheetTitle,
} from "@/registry/overlay/side-sheet/side-sheet";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/registry/overlay/tooltip/tooltip";
// Pebble: the sidebar is the desk and the content is the paper. The rail sits
// on the page colour with no chrome of its own; SidebarInset is the raised
// white card beside it. The active item is a raised pebble chip with an ember
// edge, shared through one `layoutId`, so it slides between items (nested
// ones too) instead of cross-fading.
const spring = { type: "spring", stiffness: 420, damping: 32, mass: 0.8 } as const;
const MOBILE_QUERY = "(max-width: 767px)";
type SidebarState = "expanded" | "collapsed";
type SidebarContextValue = {
state: SidebarState;
open: boolean;
setOpen: (open: boolean) => void;
isMobile: boolean;
openMobile: boolean;
setOpenMobile: (open: boolean) => void;
toggleSidebar: () => void;
shortcut: string | false;
indicatorId: string;
};
const SidebarContext = React.createContext<SidebarContextValue | null>(null);
export function useSidebar() {
const context = React.useContext(SidebarContext);
if (!context) throw new Error("useSidebar must be used within a SidebarProvider.");
return context;
}
function useIsMobile() {
// Starts false on the server and first client render, then follows the
// media query, so the markup always hydrates as the desktop layout.
const [mobile, setMobile] = React.useState(false);
React.useEffect(() => {
const query = window.matchMedia(MOBILE_QUERY);
const update = () => setMobile(query.matches);
update();
query.addEventListener("change", update);
return () => query.removeEventListener("change", update);
}, []);
return mobile;
}
export type SidebarProviderProps = React.ComponentProps<"div"> & {
/** Initial expanded state when uncontrolled. */
defaultOpen?: boolean;
/** Controlled expanded state (desktop). */
open?: boolean;
onOpenChange?: (open: boolean) => void;
/** Key that toggles the sidebar with Ctrl or Cmd. `false` turns it off. */
shortcut?: string | false;
};
export function SidebarProvider({
defaultOpen = true,
open: openProp,
onOpenChange,
shortcut = "b",
className,
style,
children,
...props
}: SidebarProviderProps) {
const isMobile = useIsMobile();
const [openMobile, setOpenMobile] = React.useState(false);
const [inner, setInner] = React.useState(defaultOpen);
const open = openProp ?? inner;
const indicatorId = React.useId();
const setOpen = React.useCallback(
(next: boolean) => {
if (openProp === undefined) setInner(next);
onOpenChange?.(next);
},
[openProp, onOpenChange],
);
const toggleSidebar = React.useCallback(() => {
if (isMobile) setOpenMobile((value) => !value);
else setOpen(!open);
}, [isMobile, open, setOpen]);
React.useEffect(() => {
if (!shortcut) return;
const onKeyDown = (event: KeyboardEvent) => {
if (event.key.toLowerCase() !== shortcut.toLowerCase()) return;
if (!(event.metaKey || event.ctrlKey) || event.altKey || event.shiftKey) return;
// Leave Cmd+B to rich-text editors (bold).
const target = event.target instanceof Element ? event.target : null;
const editable = target?.closest('[contenteditable]:not([contenteditable="false"])');
if (event.defaultPrevented || editable) return;
event.preventDefault();
toggleSidebar();
};
window.addEventListener("keydown", onKeyDown);
return () => window.removeEventListener("keydown", onKeyDown);
}, [shortcut, toggleSidebar]);
const state: SidebarState = open ? "expanded" : "collapsed";
const context = React.useMemo<SidebarContextValue>(
() => ({
state,
open,
setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar,
shortcut,
indicatorId,
}),
[state, open, setOpen, isMobile, openMobile, toggleSidebar, shortcut, indicatorId],
);
return (
<SidebarContext.Provider value={context}>
<MotionConfig reducedMotion="user">
<TooltipProvider delayDuration={0}>
<div
data-slot="sidebar-wrapper"
style={
{
"--sidebar-width": "15rem",
"--sidebar-width-icon": "3rem",
...style,
} as React.CSSProperties
}
className={cn("group/sidebar-wrapper flex min-h-0 w-full bg-background", className)}
{...props}
>
{children}
</div>
</TooltipProvider>
</MotionConfig>
</SidebarContext.Provider>
);
}
export type SidebarProps = React.ComponentProps<"div"> & {
/**
* How the sidebar collapses on desktop: to an icon rail, fully off-canvas,
* or not at all. On mobile it always opens as a left side sheet.
*/
collapsible?: "icon" | "offcanvas" | "none";
/** Accessible name for the navigation landmark. */
label?: string;
};
export function Sidebar({
collapsible = "icon",
label = "Sidebar",
className,
children,
...props
}: SidebarProps) {
const { state, isMobile, openMobile, setOpenMobile } = useSidebar();
if (isMobile) {
return (
<SideSheet open={openMobile} onOpenChange={setOpenMobile}>
<SideSheetContent
side="left"
data-slot="sidebar"
data-mobile="true"
showCloseButton={false}
className="w-(--sidebar-width) gap-0 bg-background p-0"
>
<SideSheetTitle className="sr-only">{label}</SideSheetTitle>
<SideSheetDescription className="sr-only">Site navigation</SideSheetDescription>
<nav aria-label={label} className={cn("flex h-full flex-col", className)}>
{children}
</nav>
</SideSheetContent>
</SideSheet>
);
}
const collapsed = collapsible !== "none" && state === "collapsed";
return (
<div
data-slot="sidebar"
data-state={state}
data-collapsible={collapsed ? collapsible : ""}
className={cn(
"group/sidebar relative h-full shrink-0 overflow-hidden text-foreground",
"w-(--sidebar-width) data-[collapsible=icon]:w-(--sidebar-width-icon) data-[collapsible=offcanvas]:w-0",
"transition-[width] duration-(--motion-slow) ease-move motion-reduce:transition-none",
)}
{...props}
>
{/* Fixed-width inner panel: off-canvas clips it instead of reflowing it. */}
<nav
aria-label={label}
className={cn(
"flex h-full w-(--sidebar-width) flex-col group-data-[collapsible=icon]/sidebar:w-(--sidebar-width-icon)",
"transition-[width] duration-(--motion-slow) ease-move motion-reduce:transition-none",
className,
)}
>
{children}
</nav>
</div>
);
}
export function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
return (
<main
data-slot="sidebar-inset"
className={cn(
// The paper: a raised card set into the desk with an even gutter.
"relative m-2 flex min-w-0 flex-1 flex-col overflow-hidden rounded-xl bg-card text-card-foreground",
"shadow-raised-sm ring-1 inset-shadow-highlight ring-hairline",
className,
)}
{...props}
/>
);
}
export function SidebarTrigger({ className, onClick, ...props }: React.ComponentProps<"button">) {
const { toggleSidebar, open, openMobile, isMobile, shortcut } = useSidebar();
const keys = shortcut
? `Control+${shortcut.toUpperCase()} Meta+${shortcut.toUpperCase()}`
: undefined;
return (
<button
type="button"
data-slot="sidebar-trigger"
aria-label="Toggle sidebar"
aria-expanded={isMobile ? openMobile : open}
aria-keyshortcuts={keys}
onClick={(event) => {
onClick?.(event);
if (!event.defaultPrevented) toggleSidebar();
}}
className={cn(
"inline-flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md text-muted-foreground",
"transition-[background-color,color,transform] duration-(--motion-fast) ease-enter motion-reduce:transition-none",
"hover:bg-muted hover:text-foreground active:scale-[0.94] motion-reduce:active:scale-100",
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card focus-visible:outline-none",
className,
)}
{...props}
>
<svg
viewBox="0 0 16 16"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden
className="size-4"
>
<rect x="2" y="2.75" width="12" height="10.5" rx="2.25" />
<path d="M6.25 2.75v10.5" />
<path
d="M3.9 6.5h.6M3.9 8.5h.6"
className="transition-opacity duration-(--motion-base) group-data-[state=collapsed]/sidebar-wrapper:opacity-0"
/>
</svg>
</button>
);
}
export function SidebarHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="sidebar-header"
className={cn("flex flex-col gap-2 p-2", className)}
{...props}
/>
);
}
export function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="sidebar-footer"
className={cn("mt-auto flex flex-col gap-2 p-2", className)}
{...props}
/>
);
}
export function SidebarSeparator({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
role="separator"
data-slot="sidebar-separator"
className={cn("mx-3 h-px shrink-0 bg-border", className)}
{...props}
/>
);
}
export function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="sidebar-content"
className={cn(
"flex min-h-0 flex-1 [scrollbar-width:thin] flex-col gap-1 overflow-x-hidden overflow-y-auto",
"group-data-[collapsible=icon]/sidebar:overflow-y-hidden",
className,
)}
{...props}
/>
);
}
export function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
role="group"
data-slot="sidebar-group"
className={cn("relative flex w-full min-w-0 flex-col px-2 py-1.5", className)}
{...props}
/>
);
}
export function SidebarGroupLabel({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="sidebar-group-label"
className={cn(
"flex h-7 shrink-0 items-center px-2 text-xs font-medium text-muted-foreground",
// Collapsing slides the label up under the group above and fades it,
// so the icons close ranks without a jump.
"transition-[margin,opacity] duration-(--motion-slow) ease-move motion-reduce:transition-none",
"group-data-[collapsible=icon]/sidebar:-mt-7 group-data-[collapsible=icon]/sidebar:opacity-0",
className,
)}
{...props}
/>
);
}
export function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) {
return (
<ul
data-slot="sidebar-menu"
className={cn("flex w-full min-w-0 flex-col gap-0.5", className)}
{...props}
/>
);
}
export function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
return (
<li
data-slot="sidebar-menu-item"
className={cn("group/menu-item relative", className)}
{...props}
/>
);
}
function ActiveIndicator({ sub = false }: { sub?: boolean }) {
const { indicatorId } = useSidebar();
return (
<motion.span
aria-hidden
layoutId={`${indicatorId}-active`}
transition={spring}
data-slot="sidebar-active-indicator"
className={cn(
"absolute inset-0 -z-10 rounded-md bg-card shadow-raised-xs ring-1 inset-shadow-highlight ring-hairline",
"dark:bg-muted",
)}
>
<span
className={cn(
"absolute top-1/2 left-0 h-3.5 w-[3px] -translate-x-px -translate-y-1/2 rounded-full bg-accent",
sub && "h-3",
"group-data-[collapsible=icon]/sidebar:h-3",
)}
/>
</motion.span>
);
}
const buttonSizes = {
md: "h-8 text-[13px]",
lg: "h-11 text-[13px] group-data-[collapsible=icon]/sidebar:p-0",
} as const;
export type SidebarMenuButtonProps = React.ComponentProps<"button"> & {
/** Marks the current page: draws the sliding chip and sets aria-current. */
isActive?: boolean;
/** Label shown in a tooltip while the sidebar is collapsed to icons. */
tooltip?: string;
size?: keyof typeof buttonSizes;
asChild?: boolean;
};
const menuButtonBase = cn(
"peer/menu-button relative isolate flex w-full min-w-0 cursor-pointer items-center gap-2.5 overflow-hidden rounded-md px-2 text-left outline-none select-none",
"text-muted-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate",
"transition-[background-color,color,transform] duration-(--motion-fast) ease-enter motion-reduce:transition-none",
"hover:bg-foreground/[0.045] hover:text-foreground active:scale-[0.98] motion-reduce:active:scale-100",
"focus-visible:ring-2 focus-visible:ring-ring",
"aria-[current=page]:font-medium aria-[current=page]:text-foreground aria-[current=page]:hover:bg-transparent",
"disabled:pointer-events-none disabled:opacity-50",
);
export function SidebarMenuButton({
isActive = false,
tooltip,
size = "md",
asChild = false,
className,
children,
...props
}: SidebarMenuButtonProps) {
const { state, isMobile } = useSidebar();
const Comp = asChild ? Slot.Root : "button";
// The tooltip only exists while labels are hidden. Kept controlled (rather
// than merely hiding its content) so an expanded sidebar never opens one on
// focus: Radix would still mount its screen-reader copy (role="tooltip"),
// e.g. right after a menu on this button closes and focus returns.
const [tipOpen, setTipOpen] = React.useState(false);
const showTip = state === "collapsed" && !isMobile;
const button = (
<Comp
data-slot="sidebar-menu-button"
data-size={size}
data-active={isActive || undefined}
aria-current={isActive ? "page" : undefined}
type={asChild ? undefined : "button"}
className={cn(
menuButtonBase,
"group-data-[collapsible=icon]/sidebar:size-8 group-data-[collapsible=icon]/sidebar:gap-0 group-data-[collapsible=icon]/sidebar:px-2",
// Everything after the icon (label, chevron) stays in the DOM, as it
// is the accessible name, but fades out as the rail closes over it.
"[&>:not([data-slot=sidebar-active-indicator])~*]:transition-opacity [&>:not([data-slot=sidebar-active-indicator])~*]:duration-(--motion-base)",
"group-data-[collapsible=icon]/sidebar:[&>:not([data-slot=sidebar-active-indicator])~*]:opacity-0",
buttonSizes[size],
className,
)}
{...props}
>
{asChild ? (
children
) : (
<>
{isActive && <ActiveIndicator />}
{children}
</>
)}
</Comp>
);
if (!tooltip) return button;
return (
<Tooltip open={showTip && tipOpen} onOpenChange={setTipOpen}>
<TooltipTrigger asChild>{button}</TooltipTrigger>
<TooltipContent side="right" align="center">
{tooltip}
</TooltipContent>
</Tooltip>
);
}
export type SidebarMenuBadgeProps = React.ComponentProps<"span"> & {
/** Ember tint for unread or live counts. */
tone?: "default" | "accent";
};
export function SidebarMenuBadge({
tone = "default",
className,
children,
...props
}: SidebarMenuBadgeProps) {
return (
<span
data-slot="sidebar-menu-badge"
className={cn(
"pointer-events-none absolute top-1/2 right-1.5 flex h-5 min-w-5 -translate-y-1/2 items-center justify-center rounded-full px-1.5 text-[11px] font-medium tabular-nums select-none",
tone === "accent"
? "bg-accent/12 text-accent-strong ring-1 ring-accent/30"
: "text-muted-foreground",
// Collapsed: the count becomes a dot on the icon's shoulder.
"group-data-[collapsible=icon]/sidebar:top-1 group-data-[collapsible=icon]/sidebar:right-1 group-data-[collapsible=icon]/sidebar:size-1.5 group-data-[collapsible=icon]/sidebar:min-w-0 group-data-[collapsible=icon]/sidebar:translate-y-0 group-data-[collapsible=icon]/sidebar:p-0 group-data-[collapsible=icon]/sidebar:text-[0px] group-data-[collapsible=icon]/sidebar:ring-0",
tone === "accent"
? "group-data-[collapsible=icon]/sidebar:bg-accent"
: "group-data-[collapsible=icon]/sidebar:hidden",
className,
)}
{...props}
>
{children}
</span>
);
}
export function SidebarMenuAction({ className, ...props }: React.ComponentProps<"button">) {
return (
<button
type="button"
data-slot="sidebar-menu-action"
className={cn(
"absolute top-1/2 right-1 flex size-6 -translate-y-1/2 cursor-pointer items-center justify-center rounded-md text-muted-foreground outline-none [&_svg]:size-3.5",
"transition-[background-color,color,opacity] duration-(--motion-fast) hover:bg-foreground/[0.06] hover:text-foreground",
"focus-visible:ring-2 focus-visible:ring-ring",
"group-data-[collapsible=icon]/sidebar:hidden",
className,
)}
{...props}
/>
);
}
export function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
return (
<ul
data-slot="sidebar-menu-sub"
className={cn(
// A hairline guide under the parent icon ties the children to it.
"relative ml-4 flex min-w-0 flex-col gap-0.5 border-l border-border py-0.5 pl-2",
"group-data-[collapsible=icon]/sidebar:hidden",
className,
)}
{...props}
/>
);
}
export function SidebarMenuSubItem({ className, ...props }: React.ComponentProps<"li">) {
return <li data-slot="sidebar-menu-sub-item" className={cn("relative", className)} {...props} />;
}
export type SidebarMenuSubButtonProps = React.ComponentProps<"button"> & {
isActive?: boolean;
asChild?: boolean;
};
export function SidebarMenuSubButton({
isActive = false,
asChild = false,
className,
children,
...props
}: SidebarMenuSubButtonProps) {
const Comp = asChild ? Slot.Root : "button";
return (
<Comp
data-slot="sidebar-menu-sub-button"
data-active={isActive || undefined}
aria-current={isActive ? "page" : undefined}
type={asChild ? undefined : "button"}
className={cn(menuButtonBase, "h-7 text-[13px]", className)}
{...props}
>
{asChild ? (
children
) : (
<>
{isActive && <ActiveIndicator sub />}
{children}
</>
)}
</Comp>
);
}
