CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-rc-cascader

A comprehensive cascading select component for React applications that enables hierarchical option selection through a dropdown interface

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

search.mddocs/

Search Configuration

Advanced search capabilities with filtering, custom rendering, sorting, and result limiting. Enables users to quickly find options in large hierarchical datasets through text input.

Capabilities

Search Configuration Interface

Configure search behavior with filtering, rendering, and sorting options.

interface ShowSearchType<
  OptionType extends DefaultOptionType = DefaultOptionType,
  ValueField extends keyof OptionType = keyof OptionType
> {
  /** Custom filter function for search matching */
  filter?: (
    inputValue: string,
    options: OptionType[],
    fieldNames: FieldNames<OptionType, ValueField>
  ) => boolean;
  
  /** Custom rendering for search result items */
  render?: (
    inputValue: string,
    path: OptionType[],
    prefixCls: string,
    fieldNames: FieldNames<OptionType, ValueField>
  ) => React.ReactNode;
  
  /** Custom sorting function for search results */
  sort?: (
    a: OptionType[],
    b: OptionType[],
    inputValue: string,
    fieldNames: FieldNames<OptionType, ValueField>
  ) => number;
  
  /** Whether search dropdown should match input width */
  matchInputWidth?: boolean;
  
  /** Maximum number of search results to display (false for unlimited) */
  limit?: number | false;
}

Basic Search Props

Simple search enablement and control.

interface BasicSearchProps<
  OptionType extends DefaultOptionType,
  ValueField extends keyof OptionType
> {
  /** Enable search with boolean or advanced configuration */
  showSearch?: boolean | ShowSearchType<OptionType, ValueField>;
  
  /** Controlled search input value */
  searchValue?: string;
  
  /** Search input change callback */
  onSearch?: (value: string) => void;
  
  /** Clear search value when selecting an item (multiple mode only) */
  autoClearSearchValue?: boolean;
}

Search Filter Function

Custom filtering logic for search matching.

/**
 * Custom filter function for search matching
 * @param inputValue - Current search input text
 * @param options - Array of options in the current path
 * @param fieldNames - Field name mapping configuration
 * @returns true if the path should be included in search results
 */
type SearchFilter<
  OptionType extends DefaultOptionType,
  ValueField extends keyof OptionType
> = (
  inputValue: string,
  options: OptionType[],
  fieldNames: FieldNames<OptionType, ValueField>
) => boolean;

Search Render Function

Custom rendering for search result items.

/**
 * Custom rendering for search result items
 * @param inputValue - Current search input text
 * @param path - Array of options representing the path to this result
 * @param prefixCls - CSS class prefix for styling
 * @param fieldNames - Field name mapping configuration
 * @returns Custom rendered content for the search result
 */
type SearchRender<
  OptionType extends DefaultOptionType,
  ValueField extends keyof OptionType
> = (
  inputValue: string,
  path: OptionType[],
  prefixCls: string,
  fieldNames: FieldNames<OptionType, ValueField>
) => React.ReactNode;

Search Sort Function

Custom sorting logic for search results.

/**
 * Custom sorting function for search results
 * @param a - First option path for comparison
 * @param b - Second option path for comparison
 * @param inputValue - Current search input text
 * @param fieldNames - Field name mapping configuration
 * @returns Negative, zero, or positive number for sorting order
 */
type SearchSort<
  OptionType extends DefaultOptionType,
  ValueField extends keyof OptionType
> = (
  a: OptionType[],
  b: OptionType[],
  inputValue: string,
  fieldNames: FieldNames<OptionType, ValueField>
) => number;

Usage Examples

Basic Search

import React from 'react';
import Cascader from 'rc-cascader';

const options = [
  {
    label: 'Zhejiang',
    value: 'zhejiang',
    children: [
      {
        label: 'Hangzhou',
        value: 'hangzhou',
        children: [
          { label: 'West Lake', value: 'xihu' },
          { label: 'Xiaoshan', value: 'xiaoshan' }
        ]
      },
      { label: 'Ningbo', value: 'ningbo' }
    ]
  },
  {
    label: 'Jiangsu',
    value: 'jiangsu',
    children: [
      { label: 'Nanjing', value: 'nanjing' },
      { label: 'Suzhou', value: 'suzhou' }
    ]
  }
];

const BasicSearchExample = () => {
  return (
    <Cascader
      options={options}
      showSearch
      placeholder="Search locations"
      style={{ width: 300 }}
    />
  );
};

Custom Filter Search

const CustomFilterExample = () => {
  return (
    <Cascader
      options={options}
      showSearch={{
        filter: (inputValue, path, fieldNames) => {
          // Search in any level of the path
          return path.some(option =>
            option[fieldNames.label]
              .toLowerCase()
              .includes(inputValue.toLowerCase())
          );
        }
      }}
      placeholder="Custom filter search"
    />
  );
};

Search with Custom Rendering

const CustomRenderExample = () => {
  return (
    <Cascader
      options={options}
      showSearch={{
        render: (inputValue, path, prefixCls, fieldNames) => {
          const labels = path.map(option => option[fieldNames.label]);
          const fullPath = labels.join(' / ');
          
          // Highlight matched text
          const regex = new RegExp(`(${inputValue})`, 'gi');
          const highlightedPath = fullPath.replace(
            regex, 
            '<mark>$1</mark>'
          );
          
          return (
            <div 
              className={`${prefixCls}-menu-item-search-result`}
              dangerouslySetInnerHTML={{ __html: highlightedPath }}
            />
          );
        }
      }}
      placeholder="Custom render search"
    />
  );
};

Search with Sorting and Limiting

const SortedLimitedSearchExample = () => {
  return (
    <Cascader
      options={options}
      showSearch={{
        filter: (inputValue, path) =>
          path.some(option =>
            option.label.toLowerCase().includes(inputValue.toLowerCase())
          ),
        sort: (a, b, inputValue) => {
          // Sort by relevance - exact matches first
          const aLabel = a[a.length - 1].label.toLowerCase();
          const bLabel = b[b.length - 1].label.toLowerCase();
          const input = inputValue.toLowerCase();
          
          const aExact = aLabel.startsWith(input) ? 0 : 1;
          const bExact = bLabel.startsWith(input) ? 0 : 1;
          
          if (aExact !== bExact) return aExact - bExact;
          
          // Then sort alphabetically
          return aLabel.localeCompare(bLabel);
        },
        limit: 50,
        matchInputWidth: true
      }}
      placeholder="Sorted and limited search"
    />
  );
};

Controlled Search

const ControlledSearchExample = () => {
  const [searchValue, setSearchValue] = useState('');
  const [value, setValue] = useState([]);

  return (
    <div>
      <Cascader
        options={options}
        showSearch={{
          filter: (inputValue, path) =>
            path.some(option =>
              option.label.toLowerCase().includes(inputValue.toLowerCase())
            )
        }}
        searchValue={searchValue}
        onSearch={setSearchValue}
        value={value}
        onChange={setValue}
        placeholder="Controlled search"
      />
      <p>Current search: {searchValue}</p>
      <p>Selected value: {JSON.stringify(value)}</p>
    </div>
  );
};

Search with Auto Clear

const AutoClearSearchExample = () => {
  return (
    <Cascader
      checkable
      options={options}
      showSearch
      autoClearSearchValue={true}
      placeholder="Search clears on selection"
      style={{ width: 300 }}
    />
  );
};

Advanced Multi-Field Search

const products = [
  {
    name: 'Electronics',
    id: 'electronics',
    description: 'Electronic devices and gadgets',
    children: [
      {
        name: 'Laptops',
        id: 'laptops',
        description: 'Portable computers',
        children: [
          { name: 'Gaming Laptop', id: 'gaming-laptop', description: 'High performance gaming' },
          { name: 'Business Laptop', id: 'business-laptop', description: 'Professional computing' }
        ]
      }
    ]
  }
];

const MultiFieldSearchExample = () => {
  return (
    <Cascader
      options={products}
      fieldNames={{
        label: 'name',
        value: 'id',
        children: 'children'
      }}
      showSearch={{
        filter: (inputValue, path) => {
          const input = inputValue.toLowerCase();
          return path.some(option =>
            option.name.toLowerCase().includes(input) ||
            option.description?.toLowerCase().includes(input)
          );
        },
        render: (inputValue, path) => {
          const item = path[path.length - 1];
          const pathNames = path.map(p => p.name).join(' / ');
          
          return (
            <div>
              <div style={{ fontWeight: 'bold' }}>{pathNames}</div>
              {item.description && (
                <div style={{ fontSize: '12px', color: '#666' }}>
                  {item.description}
                </div>
              )}
            </div>
          );
        }
      }}
      placeholder="Search products and descriptions"
      style={{ width: 400 }}
    />
  );
};

Search Performance Optimization

import { useMemo } from 'react';

const OptimizedSearchExample = () => {
  // Memoize search configuration to prevent re-renders
  const searchConfig = useMemo(() => ({
    filter: (inputValue, path, fieldNames) => {
      if (!inputValue) return false;
      
      const input = inputValue.toLowerCase();
      return path.some(option => {
        const label = option[fieldNames.label];
        return typeof label === 'string' && 
               label.toLowerCase().includes(input);
      });
    },
    limit: 100,
    matchInputWidth: false
  }), []);

  return (
    <Cascader
      options={options}
      showSearch={searchConfig}
      placeholder="Optimized search"
    />
  );
};

Install with Tessl CLI

npx tessl i tessl/npm-rc-cascader

docs

cascader.md

index.md

multiple-selection.md

panel.md

search.md

tile.json