Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@zhele/autocomplete

Headless React autocomplete / multiselect component with optional styles.
Lightweight, customizable, type-safe, and dependency-free — perfect for design systems and modern React apps.


✨ Features

  • 🧠 Headless-first — full control over rendering and styling
  • 🎨 Optional built-in styles
  • 🔍 Custom filtering with FilterFn
  • 🧩 Multi-select support
  • 🔧 Custom icons (React components or elements)
  • 📘 TypeScript-first
  • 📦 Zero dependencies (besides React)
  • 🪶 Small bundle size

📦 Installation

npm install @zhele/autocomplete

(Optional) import built-in styles:

import "@zhele/autocomplete/style";

🚀 Quick Start

import { useState } from "react";
import { AutocompleteJ } from "@zhele/autocomplete";
import "@zhele/autocomplete/style";

type Item = { id: number; label: string };

const items: Item[] = [
  { id: 1, label: "Apple" },
  { id: 2, label: "Banana" },
  { id: 3, label: "Orange" }
];

export function Example() {
  const [selected, setSelected] = useState<Item[]>([]);

  const toggle = (item: Item) =>
    setSelected((prev) =>
      prev.some((i) => i.id === item.id)
        ? prev.filter((i) => i.id !== item.id)
        : [...prev, item]
    );

  return (
    <AutocompleteJ
      items={items}
      selectedItems={selected}
      onToggleItem={toggle}
      placeholder="Choose fruits..."
    />
  );
}

📚 API Reference

<AutocompleteJ />

Prop Type Required Description
items T[] ✔️ All available options
selectedItems T[] ✔️ Currently selected items
onToggleItem (item: T) => void ✔️ Toggle handler
placeholder string Input placeholder
filterFn FilterFn<T> Custom filtering function
classes AutocompleteJClasses Override built-in classes
icons AutocompleteJIcons Replace internal icons
getOptionLabel (item: T) => string Custom label extractor

🔤 Types

BaseItem

export interface BaseItem {
  id: string | number;
  label?: string;
  [key: string]: unknown;
}

FilterFn<T>

export type FilterFn<T extends BaseItem> =
  (item: T, query: string) => boolean;

Example:

const startsWith: FilterFn<Item> = (item, query) =>
  item.label?.toLowerCase().startsWith(query.toLowerCase()) ?? false;

🎨 Styling

Override built-in classes

<AutocompleteJ
  ...
  classes={{
    input: "my-input",
    dropdown: "my-dropdown",
    optionChecked: "my-option-checked"
  }}
/>

Available keys:

export type AutocompleteJClasses = Partial<{
  root: string;
  form: string;
  input: string;
  clearButton: string;
  chevronButton: string;
  dropdown: string;
  option: string;
  optionChecked: string;
  optionCheckbox: string;
  optionLabel: string;
  emptyState: string;
}>;

🧩 Custom Icons

Supports both React components and React elements.

import { ChevronDown, ChevronUp, X } from "lucide-react";

<AutocompleteJ
  ...
  icons={{
    ClearIcon: <X size={24} color="red" />,
    ChevronDownIcon: <ChevronUDown />,
    ChevronUpIcon: <ChevronUp />
  }}
/>

Icon type:

export type IconJSlot = React.ElementType | React.ReactElement;

Props passed to icon components:

type IconJCommonProps = {
  size?: number;
  color?: string;
  className?: string;
};

🧪 TypeScript Example

type Item = { id: number; label: string; category: string };

const getOptionLabel = (item: Item) =>
  `${item.label} (${item.category})`;

🧩 Why This Library?

  • Clean, predictable API
  • Zero extra dependencies
  • Excellent TypeScript DX
  • Works great with:
    • TailwindCSS
    • MUI
    • Mantine
    • Chakra UI
    • Custom design systems
  • Headless-first: BYO styles and components

📜 License

MIT © Zheleznikov

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages