mtversemtverseui
Main homepage

MENU

UI ElementsFormsTablesChartsAdvanced UIExtended UI
EcommerceAnalyticsMarketingCRMStocksSaaSLogisticsAINEWSalesNEWFinanceNEW
Text GeneratorImage GeneratorCode Generator
ProductsOrdersCustomersInvoicesTransactionsCoupons
CalendarChatEmailTasksFile ManagerSupport
World MapRoute MapDensity Map
ProfileSettingsPricingFAQAPI KeysIntegrationsActivity LogNotificationsTeamSuccessBlank Page404 Error500 Error503 ErrorComing SoonMaintenance
Sign InSign UpForgot Password
Arun Pandian

Arun Pandian

arun@mtverse.io

⌘K
UI Elements/Select Menus

Select Menus

Source Free

Custom styled select dropdowns with multi-select support.

src/components/mtverse/ui-elements/index.tsx
tsx
1'use client';
2import { useState, useEffect, type ReactNode } from 'react';
3import Link from 'next/link';
4import { X, Settings, Users, Check, Code2, ChevronDown } from 'lucide-react';
5
6function SectionCard({ title, sourceSlug, children }: { title: string; sourceSlug?: string; children: ReactNode }) {
7  return (
8    <div>
9      <div className="mb-3 flex flex-wrap items-center justify-between gap-2">
10        <h3 className="text-theme-xl font-semibold text-gray-800 dark:text-white/90">{title}</h3>
11        {sourceSlug && (
12          <Link
13            href={sourceSlug}
14            className="inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium text-brand-500 transition-colors hover:bg-brand-50 dark:text-brand-400 dark:hover:bg-brand-500/10"
15          >
16            <Code2 className="size-3.5" />
17            View Source
18          </Link>
19        )}
20      </div>
21      <div className="rounded-xl border border-gray-200 bg-white p-6 dark:border-white/5 dark:bg-gray-dark">
22        {children}
23      </div>
24    </div>
25  );
26}
27
28export function SelectMenusSection() {
29  const [selected, setSelected] = useState('');
30  const [simpleSelected, setSimpleSelected] = useState('Analytics workspace');
31  const [simpleOpen, setSimpleOpen] = useState(false);
32  const [open, setOpen] = useState(false);
33  const options = ['Dashboard', 'Analytics', 'Reports', 'Settings', 'Users'];
34  const [multiSelected, setMultiSelected] = useState<string[]>(['Dashboard', 'Reports']);
35
36  useEffect(() => {
37    const handler = () => { setOpen(false); setSimpleOpen(false); };
38    if (open || simpleOpen) document.addEventListener('click', handler);
39    return () => document.removeEventListener('click', handler);
40  }, [open, simpleOpen]);
41
42  return (
43    <SectionCard title="Select Menus" sourceSlug="/ui/source/ui-elements/select-menus">
44      <div className="grid grid-cols-1 md:grid-cols-2 gap-4 max-w-2xl">`r`n        {/* Single Select */}
45        <div>
46          <label className="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">Single Select</label>
47          <div className="relative">
48            <button onClick={(e) => { e.stopPropagation(); setSimpleOpen(!simpleOpen); setOpen(false); }} className="flex w-full items-center justify-between rounded-xl border border-gray-300 bg-white px-4 py-2.5 text-sm text-gray-800 dark:border-white/10 dark:bg-gray-800 dark:text-white/90 transition-colors">
49              {simpleSelected}
50              <ChevronDown className={`size-4 text-gray-400 transition-transform ${simpleOpen ? 'rotate-180' : ''}`} />
51            </button>
52            {simpleOpen && (
53              <div className="absolute left-0 right-0 top-full z-50 mt-1 rounded-xl border border-gray-200 bg-white py-1 shadow-theme-lg dark:border-white/5 dark:bg-gray-800">
54                {options.map((opt) => (
55                  <button key={opt} onClick={(e) => { e.stopPropagation(); setSimpleSelected(opt); setSimpleOpen(false); }} className={`flex w-full items-center justify-between px-4 py-2 text-sm transition-colors ${simpleSelected === opt ? 'bg-brand-50 text-brand-600 dark:bg-brand-500/10 dark:text-brand-400' : 'text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-white/5'}`}>
56                    {opt}
57                    {simpleSelected === opt && <Check className="size-4" />}
58                  </button>
59                ))}
60              </div>
61            )}
62          </div>
63        </div>
64        {/* Custom Select */}
65        <div>
66          <label className="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">Custom Select</label>
67          <div className="relative">
68            <button onClick={(e) => { e.stopPropagation(); setOpen(!open); }} className="flex w-full items-center justify-between rounded-xl border border-gray-300 bg-white px-4 py-2.5 text-sm text-gray-800 dark:border-white/10 dark:bg-gray-800 dark:text-white/90 transition-colors">
69              {selected || 'Choose an option'}
70              <ChevronDown className={`size-4 text-gray-400 transition-transform ${open ? 'rotate-180' : ''}`} />
71            </button>
72            {open && (
73              <div className="absolute left-0 right-0 top-full z-50 mt-1 rounded-xl border border-gray-200 bg-white py-1 shadow-theme-lg dark:border-white/5 dark:bg-gray-800">
74                {options.map((opt) => (
75                  <button key={opt} onClick={() => { setSelected(opt); setOpen(false); }} className={`flex w-full items-center px-4 py-2 text-sm transition-colors ${selected === opt ? 'bg-brand-50 text-brand-600 dark:bg-brand-500/10 dark:text-brand-400' : 'text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-white/5'}`}>
76                    {opt}
77                  </button>
78                ))}
79              </div>
80            )}
81          </div>
82        </div>
83        {/* Multi-Select Tags */}
84        <div className="md:col-span-2">
85          <label className="mb-1.5 block text-sm font-medium text-gray-700 dark:text-gray-300">Multi-Select</label>
86          <div className="flex flex-wrap items-center gap-2 rounded-xl border border-gray-300 bg-white px-3 py-2 dark:border-white/10 dark:bg-gray-800">
87            {multiSelected.map((item) => (
88              <span key={item} className="inline-flex items-center gap-1 rounded-lg bg-brand-50 px-2.5 py-1 text-xs font-medium text-brand-600 dark:bg-brand-500/15 dark:text-brand-400">
89                {item}
90                <button onClick={() => setMultiSelected((p) => p.filter((x) => x !== item))} className="hover:text-brand-800 dark:hover:text-brand-300"><X className="size-3" /></button>
91              </span>
92            ))}
93            <input placeholder="Add..." className="flex-1 min-w-[80px] border-0 bg-transparent py-1 text-sm text-gray-800 placeholder-gray-400 outline-none dark:text-white/90 dark:placeholder-gray-500" onKeyDown={(e) => { if (e.key === 'Enter') { const v = e.currentTarget.value.trim(); if (v && !multiSelected.includes(v)) { setMultiSelected((p) => [...p, v]); e.currentTarget.value = ''; } e.preventDefault(); } }} />
94          </div>
95        </div>
96      </div>
97    </SectionCard>
98  );
99}

More ui elements Components

ButtonsAlertsBadgesCardsDropdownsModalsTabsAccordionsTooltipsProgressSpinnersSkeletonsAvatarsPaginationPopoversToastsTimelinesTypographyBreadcrumbEmpty StatesTag InputCode BlockDividersChipsSwitchesRadio GroupsCheckboxesText InputsTextareasSelect MenusRange SlidersFile UploadColor SwatchesIcon ShowcaseData TagsNotification BadgeStatus IndicatorCountdown TimerGradient TextAnimated UnderlineKeyboard KeysMetric CardsComparison ToggleScroll IndicatorResizable PanelCollapsible SectionsDrag Handle ListTabs with IconsVertical NavBreadcrumb with Dropdown