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

utilities.mddocs/

Common Utilities

Blueprint Select provides a comprehensive set of utilities, types, and helper functions that support all select components.

Capabilities

CSS Classes

Pre-defined CSS class constants for styling select components.

/**
 * CSS classes namespace containing all component styles
 */
namespace Classes {
  /** Multi-select component class */
  const MULTISELECT: string;
  /** Multi-select popover class */
  const MULTISELECT_POPOVER: string;
  /** Multi-select popover with default width */
  const MULTISELECT_POPOVER_DEFAULT_WIDTH: string;
  /** Multi-select popover tag input margin */
  const MULTISELECT_POPOVER_TAG_INPUT_MARGIN: string;
  /** Multi-select tag input element */
  const MULTISELECT_TAG_INPUT_INPUT: string;
  /** Omnibar component class */
  const OMNIBAR: string;
  /** Omnibar overlay class */
  const OMNIBAR_OVERLAY: string;
  /** Select popover class */
  const SELECT_POPOVER: string;
  /** Suggest popover class */
  const SUGGEST_POPOVER: string;
}

// Import as namespace from the package
import { Classes } from "@blueprintjs/select";

Usage Examples:

import { Classes } from "@blueprintjs/select";

// Using namespace import (recommended)
const CustomSelect = () => (
  <div className={`${Classes.SELECT_POPOVER} my-custom-select`}>
    {/* Select component */}
  </div>
);

// Multi-select example
const CustomMultiSelect = () => (
  <div className={`${Classes.MULTISELECT_POPOVER} my-custom-multi-select`}>
    {/* MultiSelect component */}
  </div>
);

// Target specific elements with CSS
const styles = `
  .${Classes.MULTISELECT_POPOVER} {
    min-width: 300px;
  }
  
  .${Classes.OMNIBAR_OVERLAY} {
    background-color: rgba(0, 0, 0, 0.9);
  }
`;

Item Creation Utilities

Utilities for managing "create new item" functionality.

/**
 * Branded interface for create new item markers
 */
interface CreateNewItem {
  __blueprintCreateNewItemBrand: "blueprint-create-new-item";
}

/**
 * Creates a marker object representing "create new item" option
 * @returns CreateNewItem marker object
 */
function getCreateNewItem(): CreateNewItem;

/**
 * Type guard to check if an item is a CreateNewItem marker
 * @param item - Item to check
 * @returns True if item is a CreateNewItem marker
 */
function isCreateNewItem<T>(item: T | CreateNewItem | null | undefined): item is CreateNewItem;

/**
 * Extracts the actual item from a potentially CreateNewItem value
 * @param activeItem - Item that might be a CreateNewItem marker
 * @returns The actual item or null if it was a CreateNewItem marker
 */
function getActiveItem<T>(activeItem: T | CreateNewItem | null | undefined): T | null;

Usage Examples:

import { getCreateNewItem, isCreateNewItem, getActiveItem } from "@blueprintjs/select";

// Usage in a custom item renderer
const renderItemWithCreate: ItemRenderer<string> = (item, props) => {
  if (isCreateNewItem(item)) {
    return (
      <div onClick={props.handleClick} style={{ padding: "8px", fontStyle: "italic" }}>
        Create "{props.query}"
      </div>
    );
  }
  
  return (
    <div onClick={props.handleClick} style={{ padding: "8px" }}>
      {item}
    </div>
  );
};

// Usage in active item handling
const handleActiveItemChange = (activeItem: string | CreateNewItem | null) => {
  const actualItem = getActiveItem(activeItem);
  
  if (actualItem) {
    console.log("Real item active:", actualItem);
  } else if (isCreateNewItem(activeItem)) {
    console.log("Create new item option is active");
  } else {
    console.log("No item active");
  }
};

// Creating a new item marker
const createMarker = getCreateNewItem();
console.log(isCreateNewItem(createMarker)); // true
console.log(getActiveItem(createMarker)); // null

Item Equality Utilities

Functions for comparing items for equality in select components.

/**
 * Function type for comparing two items for equality
 */
type ItemsEqualComparator<T> = (itemA: T, itemB: T) => boolean;

/**
 * Either a comparator function or a property key for equality checking
 */
type ItemsEqualProp<T> = ItemsEqualComparator<T> | keyof T;

/**
 * Executes item equality comparison using the provided equality prop
 * @param itemsEqualProp - Comparator function or property key
 * @param itemA - First item to compare
 * @param itemB - Second item to compare
 * @returns True if items are considered equal
 */
function executeItemsEqual<T>(
  itemsEqualProp: ItemsEqualProp<T> | undefined,
  itemA: T | null | undefined,
  itemB: T | null | undefined,
): boolean;

Usage Examples:

import { executeItemsEqual, ItemsEqualComparator } from "@blueprintjs/select";

interface User {
  id: number;
  name: string;
  email: string;
}

const users: User[] = [
  { id: 1, name: "Alice", email: "alice@example.com" },
  { id: 2, name: "Bob", email: "bob@example.com" },
];

// Using property key for equality
const user1 = users[0];
const user2 = { ...users[0] }; // Different object, same data

console.log(executeItemsEqual("id", user1, user2)); // true (same id)
console.log(executeItemsEqual("email", user1, user2)); // true (same email)

// Using custom comparator function
const userComparator: ItemsEqualComparator<User> = (a, b) => {
  return a.id === b.id && a.email === b.email;
};

console.log(executeItemsEqual(userComparator, user1, user2)); // true

// Usage in select components
const UserSelect = () => (
  <Select<User>
    items={users}
    itemRenderer={renderUser}
    itemsEqual="id" // Use ID for equality comparison
    onItemSelect={(user) => console.log("Selected:", user.name)}
  />
);

// Custom equality for complex objects
interface ComplexItem {
  data: { nested: { value: string } };
  metadata: Record<string, any>;
}

const complexComparator: ItemsEqualComparator<ComplexItem> = (a, b) => {
  return a.data.nested.value === b.data.nested.value;
};

const ComplexItemSelect = () => (
  <Select<ComplexItem>
    items={complexItems}
    itemRenderer={renderComplexItem}
    itemsEqual={complexComparator}
    onItemSelect={handleComplexItemSelect}
  />
);

List Rendering Utilities

Default implementation for rendering filtered item lists.

/**
 * Props passed to item list renderers
 */
interface ItemListRendererProps<T> {
  /** Currently active item */
  activeItem: T | CreateNewItem | null;
  /** Items after filtering */
  filteredItems: T[];
  /** All items before filtering */
  items: T[];
  /** Current query string */
  query: string;
  /** Ref for the items container element */
  itemsParentRef: React.Ref<HTMLUListElement>;
  /** Props for the menu container */
  menuProps?: React.HTMLAttributes<HTMLUListElement>;
  /** Function to render each individual item */
  renderItem: (item: T, index: number) => React.JSX.Element | null;
  /** Function to render the create new item option */
  renderCreateItem: () => React.JSX.Element | null | undefined;
}

/**
 * Function type for rendering the entire list of items
 */
type ItemListRenderer<T> = (itemListProps: ItemListRendererProps<T>) => React.JSX.Element | null;

/**
 * Default implementation for rendering filtered items with optional empty states
 * @param props - Item list renderer props
 * @param noResults - Content to show when no items match the filter
 * @param initialContent - Content to show when no query is entered
 * @returns Rendered item list
 */
function renderFilteredItems(
  props: ItemListRendererProps<any>,
  noResults?: React.ReactNode,
  initialContent?: React.ReactNode | null,
): React.ReactNode;

Usage Examples:

import { renderFilteredItems, ItemListRenderer } from "@blueprintjs/select";

// Custom item list renderer using the default implementation
const customItemListRenderer: ItemListRenderer<string> = (props) => {
  const noResults = <div style={{ padding: "8px", textAlign: "center" }}>No items found</div>;
  const initialContent = <div style={{ padding: "8px", color: "#666" }}>Start typing to search...</div>;
  
  return (
    <div>
      {renderFilteredItems(props, noResults, initialContent)}
    </div>
  );
};

// More complex custom renderer with sections
const sectionedItemListRenderer: ItemListRenderer<Task> = (props) => {
  const { filteredItems, renderItem } = props;
  
  if (filteredItems.length === 0) {
    return <div style={{ padding: "16px", textAlign: "center" }}>No tasks found</div>;
  }
  
  // Group by priority
  const grouped = filteredItems.reduce((acc, item, index) => {
    const priority = item.priority;
    if (!acc[priority]) acc[priority] = [];
    acc[priority].push({ item, index });
    return acc;
  }, {} as Record<string, Array<{ item: Task; index: number }>>);
  
  return (
    <div>
      {Object.entries(grouped).map(([priority, items]) => (
        <div key={priority}>
          <div style={{ padding: "8px", background: "#f5f5f5", fontWeight: "bold" }}>
            {priority.toUpperCase()} PRIORITY
          </div>
          {items.map(({ item, index }) => renderItem(item, index))}
        </div>
      ))}
    </div>
  );
};

// Using the custom renderer in a Select component
const SectionedTaskSelect = () => (
  <Select<Task>
    items={tasks}
    itemRenderer={renderTask}
    itemListRenderer={sectionedItemListRenderer}
    onItemSelect={(task) => console.log("Selected:", task.title)}
  />
);

Common Type Definitions

Shared type definitions used across all select components.

/**
 * Function to render individual items in lists
 */
type ItemRenderer<T> = (item: T, itemProps: ItemRendererProps) => React.JSX.Element | null;

/**
 * Properties passed to item renderers
 */
interface ItemRendererProps<T extends HTMLElement = HTMLLIElement> {
  /** Ref for the item element */
  ref?: React.Ref<T>;
  /** Click handler for item selection */
  handleClick: React.MouseEventHandler<HTMLElement>;
  /** Focus handler (optional) */
  handleFocus?: () => void;
  /** Item index in the list */
  index: number;
  /** Item state modifiers */
  modifiers: ItemModifiers;
  /** Current search query */
  query: string;
}

/**
 * State flags for individual items
 */
interface ItemModifiers {
  /** Whether this item is currently active/highlighted */
  active: boolean;
  /** Whether this item is disabled */
  disabled: boolean;
  /** Whether this item matches the current search predicate */
  matchesPredicate: boolean;
}

/**
 * Function to filter individual items
 */
type ItemPredicate<T> = (query: string, item: T, index?: number, exactMatch?: boolean) => boolean;

/**
 * Function to filter and transform entire item lists
 */
type ItemListPredicate<T> = (query: string, items: T[]) => T[];

/**
 * Configuration for popover behavior in select components
 */
interface SelectPopoverProps {
  /** Props for popover content container */
  popoverContentProps?: React.HTMLAttributes<HTMLDivElement>;
  /** Props for Blueprint Popover component */
  popoverProps?: Partial<Omit<PopoverProps, "content" | "defaultIsOpen" | "fill" | "renderTarget">>;
  /** Ref for accessing popover instance */
  popoverRef?: React.RefObject<Popover<DefaultPopoverTargetHTMLProps>>;
  /** Props for popover target element */
  popoverTargetProps?: React.HTMLAttributes<HTMLElement>;
}

Deprecated APIs

Legacy component names and types maintained for backward compatibility.

/** @deprecated Use MultiSelect instead */
const MultiSelect2 = MultiSelect;
/** @deprecated Use MultiSelectProps instead */
type MultiSelect2Props<T> = MultiSelectProps<T>;

/** @deprecated Use Select instead */
const Select2 = Select;
/** @deprecated Use SelectProps instead */
type Select2Props<T> = SelectProps<T>;

/** @deprecated Use Suggest instead */
const Suggest2 = Suggest;
/** @deprecated Use SuggestProps instead */
type Suggest2Props<T> = SuggestProps<T>;

Migration Examples:

// Old (deprecated) usage
import { Select2, MultiSelect2, Suggest2 } from "@blueprintjs/select";

const OldSelect = () => <Select2 items={[]} itemRenderer={() => null} onItemSelect={() => {}} />;

// New (recommended) usage
import { Select, MultiSelect, Suggest } from "@blueprintjs/select";

const NewSelect = () => <Select items={[]} itemRenderer={() => null} onItemSelect={() => {}} />;