diff --git a/docs/Styling.md b/docs/Styling.md
index fd9f4e04..a3bc7a03 100644
--- a/docs/Styling.md
+++ b/docs/Styling.md
@@ -275,121 +275,86 @@ For custom modals using `framer-motion`, apply `font-zen` to the outer container
- Tags/badges
- Helper text containers
-### Button Component
+### Button
-```typescript
-import { Button } from '@/components/ui/button';
-```
+Always use `Button` from `@/components/ui/button`.
-#### Button Variants
+```tsx
+import { Button } from '@/components/ui/button';
-Our button system uses 4 simple, purpose-driven variants:
+// Primary - main actions
+
-**default** - For buttons on background areas
-- Uses `bg-surface` color
-- Hover: Darkens slightly and increases opacity
-- Use for: Navigation buttons, actions on main background
-- Example: "Back to Markets", top-level page actions
+// Surface - actions in cards, tables
+
-**primary** - For important actions
-- Uses `bg-primary` color (primary theme color, NOT orange)
-- Hover: Increases shadow and opacity, slight scale down on click
-- Use for: Main CTAs, confirmations, primary flows
-- Example: "New Position", "Execute Rebalance", "Supply", "Withdraw"
+// Default - navigation
+
-**surface** - For buttons on surface-colored backgrounds
-- Uses `bg-hovered` color - Subtle, doesn't stand out too much
-- Hover: `bg-default-200`, Active: `bg-default-300` (gentle color progression)
-- Use for: Actions in cards, modals, table rows
-- Example: "Claim" button in tables, dropdown triggers, actions in cards
+// Ghost - icon buttons
+
+```
-**ghost** - For icon buttons and minimal actions
-- Transparent background with responsive hover states
-- Icon buttons: Scale up slightly on hover, visible background feedback
-- Size-specific hover styles for optimal feedback
-- Use for: Icon-only buttons, utility actions, settings
-- Example: Refresh icons, settings icons, filter toggles
+Variants: `primary` | `surface` | `default` | `ghost`
+Sizes: `xs` | `sm` | `md` | `lg` | `icon`
-#### Examples
+When wrapping Button in HeroUI Tooltip, wrap it in a `` to prevent ResizeObserver errors.
-```tsx
-// Primary - Important action
-
-
-// Surface - Action in a table/card (subtle)
-
-
-// Default - Navigation on background
-
-
-// Ghost - Icon-only button with tooltip (always wrap in span for HeroUI Tooltip)
-}
->
-
-
-
-
-```
+### Switch
-#### Button Sizes
+Always use `IconSwitch` from `@/components/ui/icon-switch`. Never use HeroUI Switch.
-- `xs`: Extra small (h-6, 40px min-width) - Rare use
-- `sm`: Small (h-8, 64px min-width) - Common for compact actions
-- `md`/`default`: Medium (h-10, 80px min-width) - Standard size
-- `lg`: Large (h-12, 96px min-width) - Important CTAs
-- `icon`: Icon-only (h-8 w-8, 14px icons) - Use for icon buttons
+```tsx
+import { IconSwitch } from '@/components/ui/icon-switch';
+
+// Plain switch (no icon)
+
-#### Button Hover Effects
+// With icon
+function ViewIcon({ isSelected, className }: { isSelected?: boolean; className?: string }) {
+ return isSelected ? : ;
+}
-All buttons have subtle hover refinements:
-- **Opacity**: Buttons start at 95% opacity and become 100% on hover for a refined look
-- **Color transitions**: Smooth 200ms transitions for all state changes
-- **Scale feedback**: Active state provides tactile press feedback
-- **Ghost buttons**: Size-specific hover behaviors for optimal UX
- - Icon size: Scales to 105% on hover, darker background
- - Small size: Scales to 102% on hover, medium background
- - Medium/Large: Scales to 101% on hover, lighter background
+
+```
-**Important Note**: When wrapping Button in HeroUI Tooltip, always wrap the Button in a `` to prevent ResizeObserver errors.
+Sizes: `xs` | `sm` | `md` | `lg`
-### Toggle Controls
+### Checkbox
-- Always use the shared `IconSwitch` component (`@/components/common/IconSwitch`) for boolean toggles so dimensions, motion, and iconography stay consistent across pages.
-- Prefer the `xs` size inside dense settings groups (e.g., Market Settings, global Settings). Pair the switch with a left-aligned label and secondary description beneath it to mirror existing sections.
-- Example:
+Always use `Checkbox` from `@/components/ui/checkbox`. Never use HeroUI Checkbox.
```tsx
-import { IconSwitch } from '@/components/common/IconSwitch';
+import { Checkbox } from '@/components/ui/checkbox';
-
-
-
Show Unknown Tokens
-
Display assets flagged as unverified.
-
-
-
+// Default
+
+
+// Highlighted
+
```
+Variants: `default` | `highlighted`
+
## Background, Border
- Use `bg-surface` first layer components
@@ -397,69 +362,37 @@ import { IconSwitch } from '@/components/common/IconSwitch';
## Tooltip
-Use the `TooltipContent` component for consistent tooltip styling. The component supports two modes:
-
-### Simple Tooltip (no detail)
-Shows icon, title, and optional action link on the right:
+Use `TooltipContent` from `@/components/shared/tooltip-content` for consistent tooltip styling.
```tsx
-} title="Tooltip Title" />}
->
- {/* Your trigger element */}
-
-```
-
-### Complex Tooltip (with detail)
-Shows icon, title, detail text, and optional secondary detail text:
+import { TooltipContent } from '@/components/shared/tooltip-content';
-```tsx
+// Simple
}
- title="Tooltip Title"
- detail="Main description (text-primary, text-sm)"
- secondaryDetail="Additional info (text-secondary, text-xs)"
- />
- }
+ classNames={{ base: 'p-0 m-0 bg-transparent shadow-sm border-none', content: 'p-0 m-0 bg-transparent shadow-sm border-none' }}
+ content={}
>
- {/* Your trigger element */}
+ {/* trigger */}
-```
-### Tooltip with Action Link
-Add an action link (like explorer) in the top-right corner:
+// With detail
+}
+ title="Tooltip Title"
+ detail="Main description"
+ secondaryDetail="Additional info"
+/>
-```tsx
+// With action link
}
- actionHref="https://explorer.com/address/0x123"
- onActionClick={(e) => e.stopPropagation()}
+ detail="Description"
+ actionIcon={}
+ actionHref="https://explorer.com"
/>
```
-**Important:**
-- Always use the `classNames` configuration shown above to remove HeroUI's default styling
-- `detail`: Main description text (text-primary, text-sm)
-- `secondaryDetail`: Additional info below detail (text-secondary, text-xs)
-
-## Shared UI Elements
-
-- Render token avatars with `TokenIcon` (`@/components/TokenIcon`) so chain-specific fallbacks, glyph sizing, and tooltips stay consistent.
-- Display oracle provenance data with `OracleVendorBadge` (`@/components/OracleVendorBadge`) instead of plain text to benefit from vendor icons, warnings, and tooltips.
+Always use the `classNames` configuration shown above to remove HeroUI's default styling.
### Table Component
@@ -582,190 +515,64 @@ import { TablePagination } from '@/components/common/TablePagination';
```
-**Styling Notes:**
-- Uses `font-zen !font-normal` throughout (overrides button's default font-medium)
-- All buttons have consistent 8px height (h-8)
-- Rounded-md container with bg-surface and shadow-sm
-- Primary color for active page button
-- Jump-to-page popover with Input and Go button
-- Entry count uses text-xs text-secondary
-
-### Account Identity Component
-
-**AccountIdentity** (`@/components/common/AccountIdentity`)
-- Unified component for displaying addresses, vault names, and ENS names
-- Three variants: `badge`, `compact`, `full`
-- All avatars are round by default
-
-**Variant Behaviors:**
-
-**Badge** - Minimal inline (no avatar)
-- Shows: Vault name → ENS name → Shortened address
-
-**Compact** - Avatar (16px) wrapped in badge
-- Avatar + (Vault name → ENS name → Shortened address)
-- Single badge wraps both avatar and text
-
-**Full** - Horizontal layout with all info
-- Avatar (36px) + Address badge + Extra badges (all on one line, centered)
-- **Address badge**: Always shows shortened address (e.g., 0x1234...5678), click to copy
-- **Extra badges** (shown based on conditions):
- - Connected badge (if wallet is connected)
- - ENS badge (if `showAddress=true` and no vault name)
- - Vault badge (if address is a known vault)
-
-**Styling Rules:**
-- Use `rounded-sm` for badges (not `rounded`)
-- Background: `bg-hovered` (or `bg-green-500/10` for connected)
-- Text: `font-zen` with `text-secondary` or `text-primary`
-- No underscores in variable names
-- All avatars are round
-- Full variant: all elements centered vertically
-- Smooth Framer Motion animations on all interactions
+### AccountIdentity
+
+Use `AccountIdentity` from `@/components/common/AccountIdentity` for displaying addresses, ENS names, and vault names.
```tsx
import { AccountIdentity } from '@/components/common/AccountIdentity';
-// Badge variant - minimal inline (no avatar)
-
-
-// Compact variant - avatar (16px) wrapped in badge background
-
+// Badge - minimal inline (no avatar)
+
-// Full variant - avatar + address + extra info badges
-
+// Compact - small avatar + text in badge
+
-// Full variant for vault address
-
+// Full - avatar + address badge + extra info badges
+
```
-**Props:**
-- `variant`: `'badge'` | `'compact'` | `'full'`
-- `linkTo`: `'explorer'` | `'profile'` | `'none'`
-- `showCopy`: Show copy icon at end of badge
-- `copyable`: Make entire component clickable to copy
-- `showAddress`: Show ENS badge (full variant only)
-- `showActions`: Show actions popover on click (default: `true`)
-
-**Actions Popover (Default Behavior):**
-
-By default, clicking any AccountIdentity shows a minimal popover with:
-1. **Copy Address** - Copies address to clipboard
-2. **View Account** - Navigate to positions page
-3. **View on Explorer** - Opens Etherscan in new tab
-
-To disable: `showActions={false}`
-
-```tsx
-// Default - shows actions popover on click
-
-
-// Disable actions (e.g., in dropdown menus)
-
-```
+Variants: `badge` | `compact` | `full`
-### Market Display Components
+Clicking opens actions popover (copy, view account, explorer). Disable with `showActions={false}`.
-Use the right component for displaying market information:
+### MarketIdentity
-**MarketIdentity** (`@/components/MarketIdentity`)
-- Use for displaying market info in compact rows (tables, lists, cards)
-- Shows token icons, symbols, LLTV badge, and oracle badge
-- Three modes: `Normal`, `Focused`, `Minimum`
-- Focus parameter: `Loan` or `Collateral` (affects which symbol is emphasized)
+Use `MarketIdentity` from `@/components/MarketIdentity` for displaying market info in tables, lists, and cards.
```tsx
import { MarketIdentity, MarketIdentityMode, MarketIdentityFocus } from '@/components/MarketIdentity';
-// Focused mode (default) - emphasizes one asset
-
-
// Normal mode - both assets shown equally
-
+
-// Minimum mode - only shows the focused asset (with LLTV and oracle if enabled)
+// Focused mode - emphasizes one asset
-// Wide layout - spreads content across full width (useful for tables)
-// Icon + name on left, LLTV in middle, oracle on right
+// Minimum mode - only focused asset
-```
-
-**Wide Layout:**
-
-The `wide` prop changes the layout to use `justify-between` with full width, perfect for table cells:
-- **Left side**: Token icon(s) + symbol(s)
-- **Middle**: LLTV badge (if enabled)
-- **Right side**: Oracle badge (if enabled)
+// Wide layout - for table cells
+
+```
-Works with all three modes (Normal, Focused, Minimum). Use in table cells with a fixed width for consistent alignment:
+Modes: `Normal` | `Focused` | `Minimum`
-```tsx
-
-
-
-```
+### MarketDetailsBlock
-**MarketDetailsBlock** (`@/components/common/MarketDetailsBlock`)
-- Used for previewing transactions onto a existing market.
-- Use as an expandable row in modals (e.g., supply/borrow flows)
-- Shows market state details when expanded (APY, liquidity, utilization, etc.)
-- Includes collapse/expand functionality
+Use `MarketDetailsBlock` from `@/components/common/MarketDetailsBlock` for expandable market details in modals.
```tsx
import { MarketDetailsBlock } from '@/components/common/MarketDetailsBlock';
@@ -773,73 +580,20 @@ import { MarketDetailsBlock } from '@/components/common/MarketDetailsBlock';
```
-**When to use which:**
-- Tables/Lists/Cards, Data display → Use `MarketIdentity`
-- Modal flows during a transaction, with expandable details → Use `MarketDetailsBlock`
+### TransactionIdentity
-**TransactionIdentity** (`@/components/common/TransactionIdentity`)
-- Use to display transaction hashes with explorer links
-- Consistent monospace badge styling with external link icon
-- Supports full or truncated hash display
-- Always opens in new tab with security attributes
+Use `TransactionIdentity` from `@/components/common/TransactionIdentity` for displaying transaction hashes.
```tsx
import { TransactionIdentity } from '@/components/common/TransactionIdentity';
-// Standard usage (truncated hash)
-
-
-// Full hash display
-
-
-// With custom styling
-
-```
-
-**Styling:**
-- Uses `font-monospace text-[0.65rem]` for hash display
-- Badge with `bg-hovered rounded-sm px-2 py-1`
-- Hover: `hover:bg-gray-300 hover:text-primary dark:hover:bg-gray-700`
-- External link icon (3x3) aligned with text
-- Click event stops propagation to prevent row/parent click handlers
-
-**MarketIdBadge** (`@/components/MarketIdBadge`)
-- Use to display a short market ID badge with optional network icon and warning indicator
-- Consistent styling across all tables
-- `chainId` is required
-- Warning indicator reserves space for alignment even when no warnings present
-
-```tsx
-import { MarketIdBadge } from '@/components/MarketIdBadge';
-
-// Basic usage (required chainId)
-
-
-// With network icon and warnings
-
-
+
+
```
## Input Components
diff --git a/package.json b/package.json
index 24811f9f..464f1aec 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,6 @@
"dependencies": {
"@heroicons/react": "^2.2.0",
"@heroui/accordion": "^2.0.35",
- "@heroui/checkbox": "^2.1.2",
"@heroui/input": "^2.2.2",
"@heroui/react": "^2.4.2",
"@heroui/system": "^2.2.2",
@@ -30,6 +29,7 @@
"@internationalized/date": "^3.8.2",
"@merkl/api": "^1.7.0",
"@morpho-org/blue-sdk": "^5.3.0",
+ "@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-navigation-menu": "^1.1.4",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8d36b41e..8f2606ab 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -14,9 +14,6 @@ importers:
'@heroui/accordion':
specifier: ^2.0.35
version: 2.2.21(@heroui/system@2.4.20(@heroui/theme@2.4.20(tailwindcss@4.1.17))(framer-motion@11.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@heroui/theme@2.4.20(tailwindcss@4.1.17))(framer-motion@11.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
- '@heroui/checkbox':
- specifier: ^2.1.2
- version: 2.3.24(@heroui/system@2.4.20(@heroui/theme@2.4.20(tailwindcss@4.1.17))(framer-motion@11.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@heroui/theme@2.4.20(tailwindcss@4.1.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@heroui/input':
specifier: ^2.2.2
version: 2.4.25(@heroui/system@2.4.20(@heroui/theme@2.4.20(tailwindcss@4.1.17))(framer-motion@11.18.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@heroui/theme@2.4.20(tailwindcss@4.1.17))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -41,6 +38,9 @@ importers:
'@morpho-org/blue-sdk':
specifier: ^5.3.0
version: 5.3.0(@morpho-org/morpho-ts@2.4.4)
+ '@radix-ui/react-checkbox':
+ specifier: ^1.3.3
+ version: 1.3.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@radix-ui/react-dropdown-menu':
specifier: ^2.0.6
version: 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -2257,6 +2257,19 @@ packages:
'@types/react-dom':
optional: true
+ '@radix-ui/react-checkbox@1.3.3':
+ resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+
'@radix-ui/react-collection@1.1.7':
resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==}
peerDependencies:
@@ -9292,6 +9305,22 @@ snapshots:
'@types/react': 18.3.23
'@types/react-dom': 18.3.7(@types/react@18.3.23)
+ '@radix-ui/react-checkbox@1.3.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
+ dependencies:
+ '@radix-ui/primitive': 1.1.3
+ '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1)
+ '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1)
+ '@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.23)(react@18.3.1)
+ '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.23)(react@18.3.1)
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ optionalDependencies:
+ '@types/react': 18.3.23
+ '@types/react-dom': 18.3.7(@types/react@18.3.23)
+
'@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1)
diff --git a/src/components/shared/table-pagination.tsx b/src/components/shared/table-pagination.tsx
index d9548e41..806f7896 100644
--- a/src/components/shared/table-pagination.tsx
+++ b/src/components/shared/table-pagination.tsx
@@ -3,7 +3,7 @@ import { Input, Popover, PopoverTrigger, PopoverContent, Tooltip } from '@heroui
import { ChevronLeftIcon, ChevronRightIcon, MagnifyingGlassIcon } from '@radix-ui/react-icons';
import { TooltipContent } from '@/components/shared/tooltip-content';
import { Button } from '@/components/ui/button';
-import { cn } from '@/lib/utils';
+import { cn } from '@/utils';
type TablePaginationProps = {
currentPage: number;
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index c196cec6..f109decc 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -2,7 +2,7 @@ import { forwardRef } from 'react';
import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from 'class-variance-authority';
-import { cn } from '@/lib/utils';
+import { cn } from '@/utils';
const buttonVariants = cva(
'inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium transition-all duration-200 ease-in-out border-0 outline-0 ring-0 focus:border-0 focus:outline-0 focus:ring-0 active:border-0 active:outline-0 active:ring-0 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx
new file mode 100644
index 00000000..b5f555b6
--- /dev/null
+++ b/src/components/ui/checkbox.tsx
@@ -0,0 +1,73 @@
+import * as React from "react"
+import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
+
+import { cn } from "@/utils/components"
+import { FaCheck } from "react-icons/fa6";
+type CheckboxVariant = "default" | "highlighted"
+
+type CheckboxProps = React.ComponentPropsWithoutRef & {
+ variant?: CheckboxVariant
+ label?: React.ReactNode
+}
+
+const Checkbox = React.forwardRef<
+ React.ElementRef,
+ CheckboxProps
+>(({ className, variant = "default", label, id, ...props }, ref) => {
+ // Always call useId unconditionally (Rules of Hooks)
+ const generatedId = React.useId()
+ // Auto-generate ID if label is provided but no ID is given
+ const checkboxId = id ?? (label ? generatedId : undefined)
+
+ const checkbox = (
+
+
+
+
+
+ )
+
+ // If no label, return just the checkbox
+ if (!label) {
+ return checkbox
+ }
+
+ // Highlighted variant with label
+ if (variant === "highlighted") {
+ return (
+
+ )
+ }
+
+ // Default variant with label
+ return (
+
-
-
- I understand I already deployed an autovault for this token on {getNetworkName(selectedTokenAndNetwork.networkId)}.
-
-
-
+ setAckExistingVault(checked === true)}
+ />
)}