Skip to main content

Overview

NSDropdownMenu is a comprehensive dropdown menu component that supports single and multi-select modes, searchable options, custom headers and footers, and various item types including options, dividers, and subheaders.

Key Features

Flexible Selection

Support for both single and multi-select modes

Built-in Search

Optional search functionality to filter options

Rich Item Types

Options, dividers, and subheaders for organized menus

Action Buttons

Optional Apply and Clear All buttons for batch selection

Import

import { NSDropdownMenu, NSDropdownMenuBaseItemType } from '@newtonschool/grauity';

Basic Usage

import { NSDropdownMenu, NSDropdownMenuBaseItemType } from '@newtonschool/grauity';
import { useState } from 'react';

function SingleSelectExample() {
  const [selected, setSelected] = useState(null);

  const items = [
    {
      type: NSDropdownMenuBaseItemType.OPTION,
      label: 'Option 1',
      value: 'option1',
    },
    {
      type: NSDropdownMenuBaseItemType.OPTION,
      label: 'Option 2',
      value: 'option2',
    },
    {
      type: NSDropdownMenuBaseItemType.OPTION,
      label: 'Option 3',
      value: 'option3',
    },
  ];

  return (
    <NSDropdownMenu
      items={items}
      onChange={(value) => setSelected(value)}
      value={selected}
    />
  );
}

Props

Display Configuration

showHeader
boolean
default:"true"
Whether to show the header of the dropdown menu. If false, title, overline, and subtext will be ignored.
title
string
default:"'Select'"
The title text displayed in the dropdown menu header.
overline
string
default:"''"
Small text displayed above the title in the header.
subtext
string
default:"''"
Descriptive text displayed below the title in the header.
customHeader
React.ReactNode
Custom header component. If provided, showHeader, title, overline, and subtext will be ignored.

Search Configuration

searchable
boolean
default:"false"
Whether the dropdown menu is searchable.
searchPlaceholder
string
default:"'Search'"
Placeholder text for the search input.
searchIcon
grauityIconName
default:"'search'"
Icon name for the search input.
onSearchInputChange
(value: string) => void
Callback function called when the search input value changes. If not provided, a default search method filters on label and description.

Selection Configuration

multiple
boolean
default:"false"
Whether multiple items can be selected.
items
BaseItemProps[]
required
List of items to display in the dropdown menu. Can include options, dividers, and subheaders. See Item Types below.
value
BaseItemOptionProps | BaseItemOptionProps[]
The currently selected value(s). Single object for single-select, array for multi-select.
onChange
(items: BaseItemOptionProps | BaseItemOptionProps[]) => void
Callback function called when selection changes. Returns single object or array depending on multiple prop.

Action Buttons

showActionButtons
boolean
default:"false"
Whether to show Apply and Clear All buttons. If true, onChange will only be called when Apply is clicked, not on option selection.
showClearAllButton
boolean
default:"true"
Whether to show the Clear All button (only applies when showActionButtons is true and multiple is true).
clearAllButtonText
string
default:"'Clear All'"
Text for the Clear All button.
applyButtonText
string
default:"'Apply'"
Text for the Apply button.
onClearAll
() => void
Callback function called when the Clear All button is clicked.

Advanced Configuration

applyOnOptionSelectInMultipleMode
boolean
default:"false"
In multi-select mode without action buttons, whether to call onChange immediately on option selection (true) or only when clicking outside (false).
onScrollToBottom
() => void
Callback function called when the dropdown menu is scrolled to the bottom. Useful for infinite scrolling.
emptyStateMessage
string
default:"'No options available'"
Message displayed when there are no items in the dropdown.

Styling

width
string
default:"'300px'"
The width of the dropdown menu.
maxHeight
string
default:"'500px'"
The maximum height of the dropdown menu.
className
string
Additional CSS class names for the dropdown menu.
styles
React.CSSProperties
Inline styles for the dropdown menu.
id
string
ID attribute for the dropdown menu element.

Item Types

The items prop accepts an array of different item types:

Option Item

Represents a selectable option in the dropdown:
{
  type: NSDropdownMenuBaseItemType.OPTION,
  label: 'Option Label',
  value: 'option-value',
  description: 'Optional description text',
  leftIcon: 'check-circle',
  rightIcon: 'arrow-right',
  disabled: false,
  scrollToOnOpen: false,
}
type
'option'
required
Must be NSDropdownMenuBaseItemType.OPTION.
label
string
required
The display text for the option.
value
string | number
required
The unique value for this option.
description
string
Optional description text shown below the label.
leftIcon
grauityIconName
Icon displayed on the left side of the option.
rightIcon
grauityIconName
Icon displayed on the right side of the option.
disabled
boolean
Whether the option is disabled.
scrollToOnOpen
boolean
Whether to scroll to this item when the dropdown opens.

Subheader Item

A non-selectable header to organize sections:
{
  type: NSDropdownMenuBaseItemType.SUB_HEADER,
  title: 'Section Title',
  scrollToOnOpen: false,
}
type
'subheader'
required
Must be NSDropdownMenuBaseItemType.SUB_HEADER.
title
string
required
The text to display in the subheader.

Divider Item

A visual separator between items:
{
  type: NSDropdownMenuBaseItemType.DIVIDER,
}
type
'divider'
required
Must be NSDropdownMenuBaseItemType.DIVIDER.

Advanced Examples

Organized Menu with All Item Types

import { NSDropdownMenu, NSDropdownMenuBaseItemType } from '@newtonschool/grauity';

function OrganizedMenu() {
  const items = [
    {
      type: NSDropdownMenuBaseItemType.SUB_HEADER,
      title: 'DIFFICULTY',
    },
    {
      type: NSDropdownMenuBaseItemType.OPTION,
      label: 'Easy',
      value: 'easy',
      description: 'Beginner friendly tasks',
      leftIcon: 'check-circle',
    },
    {
      type: NSDropdownMenuBaseItemType.OPTION,
      label: 'Medium',
      value: 'medium',
      description: 'Moderate challenge',
      leftIcon: 'check-circle',
    },
    {
      type: NSDropdownMenuBaseItemType.OPTION,
      label: 'Hard',
      value: 'hard',
      description: 'Advanced users only',
      leftIcon: 'check-circle',
    },
    {
      type: NSDropdownMenuBaseItemType.DIVIDER,
    },
    {
      type: NSDropdownMenuBaseItemType.SUB_HEADER,
      title: 'CATEGORIES',
    },
    {
      type: NSDropdownMenuBaseItemType.OPTION,
      label: 'Development',
      value: 'dev',
      leftIcon: 'code',
    },
    {
      type: NSDropdownMenuBaseItemType.OPTION,
      label: 'Design',
      value: 'design',
      leftIcon: 'palette',
    },
  ];

  return (
    <NSDropdownMenu
      title="Filter Tasks"
      items={items}
      searchable
    />
  );
}

Multi-Select with Action Buttons

import { NSDropdownMenu, NSDropdownMenuBaseItemType } from '@newtonschool/grauity';
import { useState } from 'react';

function MultiSelectWithActions() {
  const [selectedValues, setSelectedValues] = useState([]);

  const items = Array.from({ length: 20 }, (_, i) => ({
    type: NSDropdownMenuBaseItemType.OPTION,
    label: `Option ${i + 1}`,
    value: `option${i + 1}`,
  }));

  return (
    <NSDropdownMenu
      title="Select Multiple"
      subtext="Choose one or more options"
      multiple
      items={items}
      value={selectedValues}
      onChange={(values) => setSelectedValues(values)}
      showActionButtons
      showClearAllButton
      searchable
      onClearAll={() => setSelectedValues([])}
    />
  );
}

Custom Search Handler

import { NSDropdownMenu, NSDropdownMenuBaseItemType } from '@newtonschool/grauity';
import { useState } from 'react';

function CustomSearch() {
  const [allItems] = useState([
    // Your full list of items
  ]);
  const [filteredItems, setFilteredItems] = useState(allItems);

  const handleSearch = (searchValue: string) => {
    if (!searchValue) {
      setFilteredItems(allItems);
      return;
    }

    // Custom search logic - e.g., fuzzy search, API call, etc.
    const filtered = allItems.filter(item => 
      item.type === NSDropdownMenuBaseItemType.OPTION &&
      item.label.toLowerCase().includes(searchValue.toLowerCase())
    );
    setFilteredItems(filtered);
  };

  return (
    <NSDropdownMenu
      searchable
      onSearchInputChange={handleSearch}
      items={filteredItems}
    />
  );
}

Infinite Scroll

import { NSDropdownMenu, NSDropdownMenuBaseItemType } from '@newtonschool/grauity';
import { useState } from 'react';

function InfiniteScrollDropdown() {
  const [items, setItems] = useState(
    Array.from({ length: 20 }, (_, i) => ({
      type: NSDropdownMenuBaseItemType.OPTION,
      label: `Item ${i + 1}`,
      value: `item${i + 1}`,
    }))
  );

  const loadMore = () => {
    const currentLength = items.length;
    const newItems = Array.from({ length: 10 }, (_, i) => ({
      type: NSDropdownMenuBaseItemType.OPTION,
      label: `Item ${currentLength + i + 1}`,
      value: `item${currentLength + i + 1}`,
    }));
    setItems([...items, ...newItems]);
  };

  return (
    <NSDropdownMenu
      items={items}
      onScrollToBottom={loadMore}
      maxHeight="300px"
    />
  );
}

Behavior Notes

onChange Callback Timing:
  • Single-select without action buttons: Called immediately when an option is clicked
  • Multi-select without action buttons: Called when clicking outside the dropdown (or immediately if applyOnOptionSelectInMultipleMode is true)
  • With action buttons: Called only when the Apply button is clicked
Search Behavior: When searchable is true and no onSearchInputChange is provided, the component uses a default search method that filters items based on their label and description properties.

Accessibility

The component includes proper ARIA attributes and keyboard navigation:
  • Use Arrow Up and Arrow Down to navigate options
  • Press Enter to select an option
  • Press Escape to apply changes (when action buttons are not shown)
  • Search input is automatically focused when searchable is true

Use Cases

Use dropdown menus to create powerful filter interfaces with multiple selection options and categories.
Multi-select mode is perfect for allowing users to select multiple tags or categories.
Organize related settings using subheaders and dividers for a clean, organized interface.
Provide column filtering or bulk action selection in data table interfaces.

Build docs developers (and LLMs) love