npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

accessible-search-select

v0.0.4

Published

Un componente de selección con buscador integrado, reutilizable y tipado en TypeScript. Soporta selección única o múltiple y filtrado en memoria.

Readme

Accessible Search Select

Un componente de selección con buscador integrado, reutilizable y tipado en TypeScript.
Soporta selección única o múltiple y filtrado en memoria.

Flujo de funcionamiento


Instalación

npm install accessible-search-select
# o
yarn add accessible-search-select

Requisitos

Esta librería utiliza React hooks, por lo que necesita que React esté instalado en tu proyecto.

npm install react react-dom

Uso básico

import { SelectSearch } from "accessible-search-select";

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

const users: User[] = [
  { id: 1, name: "Juan" },
  { id: 2, name: "María" },
  { id: 3, name: "Pedro" },
];

export default function App() {
  return (
    <SelectSearch<User>
      options={users}
      optionLabel="name"
      optionValue="id"
      onChange={(value) => console.log("Seleccionado:", value)}
      placeholder="Buscar usuario..."
      noResultsText="Sin resultados"
    />
  );
}

💡 Nota: El tipo User es solo un ejemplo. El componente SelectSearch es genérico (<T>) y funciona con cualquier estructura de datos.


Props

| Prop | Tipo | Requerido | Descripción | |------|------|-----------|-------------| | options | T[] | ✅ | Lista de opciones a mostrar. | | optionLabel | keyof T | ✅ | Clave del objeto que se mostrará como texto en la lista. | | optionLabel2 | keyof T | ❌ | Clave opcional del objeto que se mostrará como texto secundario (entre paréntesis). | | optionValue | keyof T | ✅ | Clave del objeto que se usará como valor único de la opción. | | value | T \| T[] | ❌ | Valor actual (single o multiple). | | onChange | (value: T \| T[] \| null) => void | ✅ | Se ejecuta al seleccionar/deseleccionar opciones. | | multiple | boolean | ❌ | Habilita selección múltiple. Default: false. | | placeholder | string | ❌ | Texto del input de búsqueda. | | ariaInputLabel | string | ❌ | Texto accesible para el input. Default: "Buscar opción". | | ariaListboxLabel | string | ❌ | Texto accesible para el listbox. Default: "Opciones disponibles". | | noResultsText | string | ❌ | Texto mostrado si no hay coincidencias. | | className | string | ❌ | Clase CSS personalizada para el contenedor. |


Ejemplo con selección múltiple controlada (useState)

import { useState } from "react";
import { SelectSearch } from "accessible-search-select";

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

const users: User[] = [
  { id: 1, name: "Juan" },
  { id: 2, name: "María" },
  { id: 3, name: "Pedro" },
];

export default function App() {
  const [selectedUsers, setSelectedUsers] = useState<User[] | null>([]);

  return (
    <div>
      <SelectSearch<User>
        options={users}
        optionLabel="name"
        optionValue="id"
        multiple
        value={selectedUsers}
        onChange={setSelectedUsers}
        placeholder="Buscar..."
        noResultsText="Nada encontrado"
      />

      {selectedUsers && selectedUsers.length > 0 && (
        <p>
          Usuarios seleccionados:{" "}
          {selectedUsers.map(u => u.name).join(", ")}
        </p>
      )}
    </div>
  );
}

Flujo de funcionamiento

La búsqueda actualiza searchTerm, se filtran las opciones y se renderiza la lista.
Al seleccionar, se llama onChange devolviendo un elemento único o un array según multiple.

Flujo de funcionamiento con ARIA

Accesibilidad:

El componente está diseñado para ser completamente accesible, compatible con lectores de pantalla y navegación con teclado.

  • El input utiliza aria-label (o ariaInputLabel) para describir su función.
  • La lista utiliza role="listbox" y aria-multiselectable si es selección múltiple.
  • Cada elemento utiliza role="option" y aria-selected según su estado.
  • La navegación con teclado mantiene aria-activedescendant apuntando al elemento resaltado (highlightedIndex), aunque no haya focus real en el li.

Personalización con CSS

Puedes pasar tu propia clase al componente usando la prop className para aplicar estilos externos a los elementos internos (input, ul, li).

import "accessible-search-select/style.css"; // Importa los estilos por defecto (opcional)

<SelectSearch<User>
  className="mi-select-search"
  options={users}
  optionLabel="name"
  optionValue="id"
  onChange={(v) => console.log(v)}
  placeholder="Buscar..."
/>

Clases internas

El componente utiliza las siguientes clases para aplicar estilos, siguiendo la convención BEM:

| Clase | Descripción | |-------|------------| | select-search__container | Contenedor principal del componente. | | select-search__input | El input de búsqueda. | | select-search__list | Lista (ul) que contiene los elementos filtrados. | | select-search__item | Cada elemento (li) de la lista. | | select-search__label2 | Texto secundario opcional (derivado de optionLabel2). Aparece entre paréntesis junto al label principal. | | select-search__item--highlighted | Modificador visual para el elemento actualmente resaltado por navegación con teclado (no es focus real; se usa con aria-activedescendant). | | select-search__item--selected | Modificador para un elemento seleccionado. | | select-search-no-results | Mensaje que aparece cuando no hay resultados. |

💡 Nota: Las clases listadas arriba ya vienen preestilizadas en el CSS que exporta la librería, pero puedes sobrescribir sus estilos usando tu propia clase a través de la prop className.

CSS externo (personalizable)

/* =============================
   Contenedor principal (opcional)
   ============================= */
.mi-select-search {
  /* Estilos para el contenedor principal */
}

/* =============================
   Input de búsqueda
   ============================= */
.mi-select-search .select-search__input {
  /* Sobrescribe estilos si lo deseas */
}

/* =============================
   Lista de opciones
   ============================= */
.mi-select-search .select-search__list {
  /* Sobrescribe estilos si lo deseas */
}

/* =============================
   Elemento de lista
   ============================= */
.mi-select-search .select-search__item {
  /* Estilos base para cada opción */
}

/* =============================
   Segundo label opcional
   ============================= */
.mi-select-search .select-search__label2 {
  /* Sobrescribe/resalta estilos si lo deseas */
}

/* =============================
   Elemento actualmente resaltado
   ============================= */
.mi-select-search .select-search__item--highlighted {
  /* Resalta el item seleccionado por teclado */
}

/* =============================
   Elemento seleccionado
   ============================= */
.mi-select-search .select-search__item--selected {
  /* Estilos para la opción seleccionada */
}

/* =============================
   Mensaje de "sin resultados"
   ============================= */
.mi-select-search .select-search-no-results {
  /* Estilos para el mensaje */
}

💡 Nota: Al pasar tu propia clase al componente mediante la prop className, puedes sobrescribir los estilos de las clases internas (select-search__input, select-search__list, select-search__item, etc.) que ya vienen preestilizadas en el CSS de la librería.

Estructura interna

Estructura HTML del SelectSearch

En la imagen puedes ver la estructura interna del componente: un input seguido por un ul con li para cada opción.

Licencia

MIT