or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.mdmulti-select.mdomnibar.mdquery-list.mdselect.mdsuggest.mdutilities.md
tile.json

select.mddocs/

Single Item Selection

The Select component allows users to choose one item from a dropdown list with optional filtering capabilities.

Capabilities

Select Component

React component for single item selection from a dropdown list.

/**
 * Select component for choosing one item from a dropdown list
 * @template T - Type of items in the list
 */
class Select<T> extends React.Component<SelectProps<T>, SelectState> {
  /** Generic factory method for type inference */
  static ofType<U>(): new (props: SelectProps<U>) => Select<U>;
  
  /** Reference to the input element */
  inputElement: HTMLInputElement | null;
}

interface SelectProps<T> extends ListItemsProps<T>, SelectPopoverProps {
  /** Child element that triggers the popover (typically a button) */
  children?: React.ReactNode;
  /** Whether the select is disabled */
  disabled?: boolean;
  /** Whether the select should fill its container */
  fill?: boolean;
  /** Whether to show a filter input in the dropdown */
  filterable?: boolean;
  /** Props for the filter input when filterable is true */
  inputProps?: Partial<Omit<InputGroupProps, "value" | "onChange">>;
  /** Props for the dropdown menu container */
  menuProps?: React.HTMLAttributes<HTMLUListElement>;
  /** Placeholder text for the filter input */
  placeholder?: string;
  /** Whether to reset the query when the popover closes */
  resetOnClose?: boolean;
}

interface SelectState {
  /** Whether the dropdown is currently open */
  isOpen: boolean;
}

Usage Examples:

import React, { useState } from "react";
import { Select, ItemRenderer } from "@blueprintjs/select";
import { Button, MenuItem } from "@blueprintjs/core";

interface City {
  name: string;
  country: string;
  population: number;
}

const cities: City[] = [
  { name: "New York", country: "USA", population: 8400000 },
  { name: "London", country: "UK", population: 9000000 },
  { name: "Tokyo", country: "Japan", population: 14000000 },
];

const renderCity: ItemRenderer<City> = (city, { handleClick, modifiers, query }) => (
  <MenuItem
    key={`${city.name}-${city.country}`}
    text={`${city.name}, ${city.country}`}
    label={city.population.toLocaleString()}
    onClick={handleClick}
    active={modifiers.active}
    disabled={modifiers.disabled}
  />
);

const CitySelect = () => {
  const [selectedCity, setSelectedCity] = useState<City | null>(null);

  return (
    <Select<City>
      items={cities}
      itemRenderer={renderCity}
      onItemSelect={setSelectedCity}
      noResults={<MenuItem disabled text="No cities found." />}
      filterable
      resetOnClose
    >
      <Button
        text={selectedCity ? `${selectedCity.name}, ${selectedCity.country}` : "Select a city..."}
        rightIcon="caret-down"
      />
    </Select>
  );
};

// With custom filtering
const cityPredicate = (query: string, city: City) => {
  return (
    city.name.toLowerCase().includes(query.toLowerCase()) ||
    city.country.toLowerCase().includes(query.toLowerCase())
  );
};

const FilteredCitySelect = () => (
  <Select<City>
    items={cities}
    itemRenderer={renderCity}
    itemPredicate={cityPredicate}
    onItemSelect={(city) => console.log("Selected:", city)}
  >
    <Button text="Select city with custom filter..." rightIcon="caret-down" />
  </Select>
);

Popover Configuration

Select components support extensive popover customization through SelectPopoverProps.

interface SelectPopoverProps {
  /** Props passed to the popover content container */
  popoverContentProps?: React.HTMLAttributes<HTMLDivElement>;
  /** Props passed to the Blueprint Popover component */
  popoverProps?: Partial<Omit<PopoverProps, "content" | "defaultIsOpen" | "fill" | "renderTarget">>;
  /** Ref to access the popover instance */
  popoverRef?: React.RefObject<Popover>;
  /** Props passed to the popover target element */
  popoverTargetProps?: React.HTMLAttributes<HTMLElement>;
}

Usage Examples:

import { Select } from "@blueprintjs/select";
import { Button } from "@blueprintjs/core";

// Customize popover positioning and behavior
const CustomPopoverSelect = () => (
  <Select<string>
    items={["Option 1", "Option 2", "Option 3"]}
    itemRenderer={(item, { handleClick, modifiers }) => (
      <div onClick={handleClick} style={{ padding: "8px" }}>
        {item}
      </div>
    )}
    onItemSelect={(item) => console.log(item)}
    popoverProps={{
      position: "bottom-left",
      minimal: true,
      modifiers: {
        preventOverflow: { enabled: true },
      },
    }}
    popoverContentProps={{
      style: { minWidth: "200px" },
    }}
  >
    <Button text="Custom popover..." />
  </Select>
);

Advanced Filtering

Select supports both item-level and list-level filtering predicates.

// From common types
type ItemPredicate<T> = (query: string, item: T, index?: number, exactMatch?: boolean) => boolean;
type ItemListPredicate<T> = (query: string, items: T[]) => T[];

Usage Examples:

// Item predicate - filters individual items
const itemPredicate: ItemPredicate<City> = (query, city, index, exactMatch) => {
  if (exactMatch) {
    return city.name.toLowerCase() === query.toLowerCase();
  }
  return (
    city.name.toLowerCase().includes(query.toLowerCase()) ||
    city.country.toLowerCase().includes(query.toLowerCase())
  );
};

// List predicate - custom sorting and filtering
const itemListPredicate: ItemListPredicate<City> = (query, cities) => {
  if (!query) return cities;
  
  const filtered = cities.filter(city =>
    city.name.toLowerCase().includes(query.toLowerCase()) ||
    city.country.toLowerCase().includes(query.toLowerCase())
  );
  
  // Sort by relevance
  return filtered.sort((a, b) => {
    const aStartsWithQuery = a.name.toLowerCase().startsWith(query.toLowerCase());
    const bStartsWithQuery = b.name.toLowerCase().startsWith(query.toLowerCase());
    
    if (aStartsWithQuery && !bStartsWithQuery) return -1;
    if (!aStartsWithQuery && bStartsWithQuery) return 1;
    return a.name.localeCompare(b.name);
  });
};

const AdvancedFilterSelect = () => (
  <Select<City>
    items={cities}
    itemRenderer={renderCity}
    itemListPredicate={itemListPredicate}
    onItemSelect={(city) => console.log("Selected:", city)}
    filterable
  >
    <Button text="Advanced filtering..." />
  </Select>
);