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 🙏

© 2024 – Pkg Stats / Ryan Hefner

typeahead-standalone

v5.4.0

Published

A fast fully-featured standalone autocomplete library

Downloads

30,091

Readme

Typeahead-standalone.js

npm version Build Status code style CDN Hits Downloads maintained License speed blazing Donate


A fast fully-featured standalone autocomplete library

🌟 Highlights 🌟

  • 🚀 Blazing fast suggestions and autocompletion
  • 📦 Has 0 DEPENDENCIES! Written in pure JS (typescript)
  • 🎀 Framework agnostic! Usable with any framework (React, Vue, Svelte, etc)
  • 💡 Highly customizable and light-weight <5kb minzipped
  • ⚜️ In-built support for multiple data sources - Local, Prefetch and Remote (requests rate-limited by default)
  • ⚡️ Suggestions calculated via a very efficient algorithm based on trie data structure
  • ♿️ WAI-ARIA compliant design pattern with support for language diacritics
  • 🌐 Supports every major browser!

🔥 Demo/Docs

Find here detailed Docs with Live Demos for typeahead-standalone.js.

Preview of a basic example:

Basic example

➕ Install

# you can install typeahead with npm
$ npm install --save typeahead-standalone

# Alternatively you can use Yarn
$ yarn add typeahead-standalone

Then include the library in your App/Page.

As a module,

// using ES6 modules
import typeahead from 'typeahead-standalone'; // imports library (js)
import 'typeahead-standalone/dist/basic.css'; // imports basic styles (css)

// using CommonJS modules
const typeahead = require('typeahead-standalone');
require('typeahead-standalone/dist/basic.css');

In the browser context,

<!-- Include the basic styles & the library -->
<link rel="stylesheet" href="./node_modules/typeahead-standalone/dist/basic.css" />
<script src="./node_modules/typeahead-standalone/dist/typeahead-standalone.umd.js"></script>

<!-- Alternatively, you can use a CDN. For example, use jsdelivr to get the latest version -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeahead-standalone/dist/basic.css" />
<script src="https://cdn.jsdelivr.net/npm/typeahead-standalone"></script>

<!-- or use unpkg.com to get a specific version -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/basic.css" />
<script src="https://unpkg.com/[email protected]/dist/typeahead-standalone.umd.js"></script>

The library will be available as a global object at window.typeahead

🌱 Usage

Typeahead requires an input Element to attach itself to, and a Data source (local/remote) to display suggestions.

Here is a very basic example (See demo for advanced examples)

Html

<!-- include the library -->
<script src="..." async></script>

<!-- Html markup -->
<input type="search" id="searchInput" autocomplete="off" placeholder="Search...">

Javascript

// local Data
const colors = ['Grey', 'Brown', 'Black', 'Blue'];

// input element to attach to
const inputElement = document.getElementById("searchInput");

typeahead({
    input: inputElement,
    source: {
      local: colors,
      // prefetch: {...}
      // remote: {...}
    }
});

🔧 Configuration

You can pass the following config options to typeahead-standalone:

| Parameter | Description | Default | | --------- | ----------- | ------- | |input|DOM input element must be passed with this parameter and typeahead will attach itself to this field. |- (Required)| |source|This is the source of Data from which suggestions will be calculated. The source can be local, prefetched or retrieved from a remote endpoint. Details |- (Required)| |minLength|Specify the minimum length, when suggestions should appear on the screen.|1| |limit|Specify the maximum number of suggestions that should be displayed.|5| |highlight| The matched letters from the query are highlighted in the list of suggestions. A class tt-highlight is added to facilitate styling|true| |autoSelect| If set to true, pre-selects the first displayed suggestion |false| |hint| Updates the input placeholder to be equal to the first matched suggestion. A class tt-hint is added to facilitate styling|true| |diacritics| Flag to enable/disable language diacritics supported search (i.e. search by converting accented characters into their non-accented counterparts)|undefined| |classNames: Object|The classNames object can be used to set custom classes for every html element that is injected in the DOM. Details |undefined| |templates|An object containing templates for header, footer, suggestion, group and notFound state. See templates section for clarification |undefined| |preventSubmit|If your input element is used inside a form element, this flag allows to prevent the default submit action when the ENTER key is pressed.|false| |onSubmit(event, selectedItem?)|When you want to use typeahead outside a form element, this handler can be used to process/submit the input value. Gets triggered on hitting the ENTER key. First parameter is the keyboard Event and the 2nd parameter is the selected item or undefined if no item was selected|undefined| |display(selectedItem, event?) => string|This callback is executed when the user selects an item from the suggestions. The current suggestion/item is passed as a parameter and it must return a string which is set as the input's value. The 2nd optional parameter event is a Mouse/Keyboard event which can be used to track user interaction or for analytics. It defaults to null. |Returns the string representation of the selected item| |tokenizer?: (words: string) => string[]|The tokenizer function is used to split the search query and the search data by a given character(s). This function is useful when you wish to search hypenated-words or words with a certain prefix/suffix |words are split by space characters (new line, tab, spaces)| |listScrollOptions?: ScrollIntoViewOptions| Allows fine control over the scroll behaviour for a large list of suggestions that needs scrolling. These options are passed to the scrollIntoView() function. MDN Ref | { block: "nearest", inline: "nearest", behaviour: "auto"}| |retainFocus| This parameter is useful to control the focus on pressing the "Tab" key when the list of suggestions is open. If enabled, it selects the highlighted option & then returns the focus to the search input. If disabled, pressing "Tab" will select the highlighted option & take the focus away to the next focussable item in your form | true| |hooks| The hooks config option is useful to execute arbitrary code at specific moments in typeahead's lifecycle. Details | undefined |


🔌 Source

This is the source of data from which suggestions will be provided. This is the expected format of the source object.

source: {
  local: [],
  remote: {
    url: 'https://remoteapi.com/%QUERY', // OR "url: (inputQuery: string) => `https://remoteapi.com/${inputQuery}`"
    wildcard: '%QUERY',
    debounce: 300             // optional, default => 200ms
    requestOptions: {}        // optional, default => undefined
  },
  prefetch: {
    url: 'https://remoteapi.com/load-suggestions', // OR `url: () => string`
    when: 'onFocus',          // optional, default => 'onInit'
    done: false,              // optional, default => false
    process: (items) => void, // optional, default => undefined
    requestOptions: {}        // optional, default => undefined
  },
  keys: ['...'],        // optional  (required when source => Object[])
  groupKey: '...',     // optional, default => undefined
  identity: (item) => string, // optional (determines uniqueness of each suggestion)
  transform: function (data) {
    // modify source data if needed & return it
    return data;
  }
}
  • Local: The local data source is used when you want to provide suggestions from a local source like a variable.
  • Prefetch: The prefetch data source is used when you want to preload suggestions from a remote endpoint in advance. You must provide the url parameter that points to the endpoint that will return suggestions. You can provide an optional when parameter which defines when the prefetch request should occur. It defaults to onInit meaning that suggestions will be preloaded as soon as typeahead gets initialized. You can set it to onFocus which will cause suggestions to be preloaded only when the user focuses the search input box. The done flag is optional & can be used to disable the prefetch request programmatically. Its default value is false. It gets set to true automatically when data is prefetched for the first time (to prevent multiple network requests). By setting done: true, the prefetch request will not occur. An example use-case to do this is when you are using localStorage to store suggestions but the localStorage already had stored suggestions previously thereby eliminating the need to prefetch data again. The process(suggestions) callback is optional. It gets executed after the prefetch request occurs. It receives the transformed suggestions as a parameter & as an example can be used to store the received suggestions in localStorage to be used later.
  • Remote: The remote data source is used when you want to interrogate a remote endpoint to fetch data.
  • Wildcard: While using the remote data source, you must set the url and the wildcard options. wildcard will be replaced with the search string while executing the request.
  • Debounce: The debounce option is used to delay execution of http requests (in milliseconds). It is optional & it defaults to 200ms.
  • RequestOptions: The fetch API is used to query remote endpoints. You may provide an object of requestOptions to customize the outgoing request. By default the query type is GET.
  • Transform: You can provide an optional transform() function which gets called immediately after the prefetch/remote endpoint returns a response. You can modify the response before it gets processed by typeahead.
  • Keys: The keys array is required when the data source is an array of objects. The first key is used to identify which property of the object should be used as the text for displaying the suggestions. For example, lets say the data source is something like this:
/* Example Data source */
[
  { id: 1, color: "Yellow", meta: { colorCode: "YW" }},
  { id: 2, color: "Green", meta: { colorCode: "GN"}, shade: "Greenish" },
  { id: 3, color: "Olive", meta: { colorCode: "OV"}, shade: "Greenish" },
  ...
]

Now if we wish to use the the text defined in the color property to appear as the suggestions, then the keys must be include color as the first key. (i.e. keys: ["color"]).

If you wish to add more properties to the search index, you can specify those properties as well in the keys array. This can be best understood with an example. Lets take the same example data source as shown above. What if you wanted to search colors by another property(colorCode) and not just by its color ? To do so, simply set keys: ["color", "meta.colorCode"]. If you now search for "YW", the suggestion "Yellow" pops up as expected.

  • groupKey: If you wish to group your suggestions, set the groupKey config option. Again, going with the same example data source as above, when you set groupKey: "shade", suggestions will be grouped by the property "shade". In this example, the colors Green and Olive will appear under the group "Greenish" (shade) whereas the color Yellow will have no group. groupKey also supports accessing nested properties using dot notation. (example - groupKey: "category.title")
  • identity: The identity() function is used to determine uniqueness of each suggestion. It receives the suggestion as a parameter and must return a string unique to the given suggestion. This is an optional property and it defaults to returning the value associated with the first key i.e. keys[0]. However, the default value might not work everytime. For example, consider the following code -
/* Example Data source of Songs */
[
  { title: "God is Good", artist: "Don Moen" },
  { title: "God is Good", artist: "Paul Wilbur" },
  { title: "God is Good", artist: "Micheal Smith" },
  { title: "El Shaddai", artist: "Amy Grant" },
  ...
]

Lets assume the keys is set to keys: ["title"]. By default the identity() function uses the first key (i.e. the title) to determine uniqueness. So if you search for God, you will find only 1 suggestion displayed since there are 3 songs with the exact same title property. In order to show all 3 suggestions with different artists, you need to set the identity property such that it returns a unique string -

identity(item) => `${item.title}${item.artist}`;

It is highly recommended to set the identity() config option to return a unique string when your data source is an array of Objects.

Checkout the Live Examples for further clarification.


🪝 Hooks

Currently there is only 1 hook available:

  1. updateHits: async (resultSet, loader) => Promise<resultSet> which is executed just before the search results are displayed to the user & can be used to override the suggestions returned by the search index. (useful for custom sorting, filtering, adding or removing results. This hook is an async function allowing you to make AJAX requests to fetch new results if needed)
// Example usage of "updateHits" hook
typeahead({
  input: document.querySelector(".myInput"),
  source: {
    local: [],
    // ...
  },
  hooks: {
    updateHits: async (resultSet, loader) => {
      resultSet.hits.push({name: "new suggestion"}); // add new suggestion
      // resultSet.hits.filter( ... ); // filter the suggestions
      // resultSet.hits.sort( ... );   // custom sort the suggestions
      // resultSet.count = 5000;       // to set the total results found

      /*** You can also make an AJAX request to fetch results ***/
      // loader(); // display the loader template
      // const response = await fetch('https://example.com');
      // const text = await response.text();
      // resultSet.hits = text && JSON.parse(text);
      // loader(false); // hide the loader template

      // resultSet.updateSearchIndex = true; // updates search index if necessary. Default `false`

      return resultSet; // you must return the resultSet
    },
  },
  templates: {
    loader: () => { ... },
  }
});

🎨 Styling (css)

Some basic styling is provided with typeahead. The UI is completely upto you and is customizable to the very pixel. You can use the following classes to add/override styles.

  • The entire html is wrapped in a container with a class typeahead-standalone.
  • The input element has a tt-input class.
  • The hint element has a tt-hint class.
  • The list of suggestions is wrapped in a container with a tt-list class. (A class tt-hide is added when no suggestions are available)
  • Each suggestion has a class tt-suggestion and if the suggestion is selected, then it has a tt-selected class additionally.
  • If the highlight config option is set to true, every highlighted text block has a tt-highlight class.

You can add your own styles by targetting the parent selector .typeahead-standalone. For example, we can update the background color of every suggestion as seen below -

/* set background color for each suggestion */
.typeahead-standalone .tt-list .tt-suggestion {
  background-color: green;
}

To override default styling, set the config option className and use it as a selector. Lets say you set className: "my-typeahead", then to override style on hovering/selecting a suggestion, you could use:

/* override styles */
.typeahead-standalone.my-typeahead .tt-list .tt-suggestion:hover,
.typeahead-standalone.my-typeahead .tt-list .tt-suggestion.tt-selected {
 color: black;
 background-color: white;
}

Starting with v4.0, the JS and CSS has been separated allowing greater control over the style. The entire css can be retrieved either from the CDN or from below and be copied directly into your project allowing you to discard/override any styles as necessary.

/***** basic styles *****/
.typeahead-standalone {
  position: relative;
  text-align: left;
  color: #000;
}
.typeahead-standalone .tt-input {
  z-index: 1;
  background: transparent;
  position: relative;
}
.typeahead-standalone .tt-hint {
  position: absolute;
  left: 0;
  cursor: default;
  user-select: none;
  background: #fff;
  color: silver;
  z-index: 0;
}
.typeahead-standalone .tt-list {
  background: #fff;
  z-index: 1000;
  box-sizing: border-box;
  overflow: auto;
  border: 1px solid rgba(50, 50, 50, 0.6);
  border-radius: 4px;
  box-shadow: 0px 10px 30px 0px rgba(0, 0, 0, 0.1);
  position: absolute;
  max-height: 70vh;
}
.typeahead-standalone .tt-list.tt-hide {
  display: none;
}
.typeahead-standalone .tt-list div[class^="tt-"] {
  padding: 0 4px;
}
.typeahead-standalone .tt-list .tt-suggestion:hover,
.typeahead-standalone .tt-list .tt-suggestion.tt-selected {
  background: #55acee;
  cursor: pointer;
}
.typeahead-standalone .tt-list .tt-suggestion .tt-highlight {
  font-weight: 900;
}
.typeahead-standalone .tt-list .tt-group {
  background: #eee;
}

You can also use templates to add a header, footer and further style each suggestion.

💫 Templates

Templates can be used to customize the rendering of the List. Their usage is completely optional. Currently, there are 7 templates available -

templates: {
  header: (resultSet) => '<h1>List of Countries</h1>', /* Rendered at the top of the dataset */
  footer: (resultSet) => '<div>See more</div>', /* Rendered at the bottom of the dataset */
  suggestion: (item, resultSet) => {   /* Used to render a single suggestion */
    return `<div class="custom-suggestion">${item.label}</div>`;
  },
  group: (groupName, resultSet) => {   /* Used to render a group */
    return `<div class="custom-group">${groupName}</div>`;
  },
  empty: (resultSet) => {   /* Rendered when the input query is empty */
    return `<div>Search for Colors...</div>`;
    // OR (to display some suggestions by default)
    return [{title: "France"}, {title: "Spain"}];
  }
  loader: () => 'Loading...', /* Rendered while awaiting data from a remote source */
  notFound: (resultSet) => '<span>Nothing Found</span>', /* Rendered if no suggestions are available */
}

As seen above, each template takes a callback that must return a string which is later interpreted as HTML. The templates also receive a parameter resultSet that has a structure as shown below.

resultSet = {
  query: '...', // the input query
  hits: [...], // found suggestions
  count: 0,     // the total suggestions found in the search index
  limit: 5,     // the number of suggestions to show
  wrapper: DOMElement,  // the container DOM element
}

To facilitate styling, each template is wrapped in a div element with a corresponding class. i.e.

  • header => class tt-header
  • footer => class tt-footer
  • suggestion => class tt-suggestion
  • group => class tt-group
  • loader => class tt-loader
  • empty => class tt-empty
  • notFound => class tt-notFound

🖌 ClassNames

The classNames configuration option simply allows you to replace the default class names as per your choice.

The default class names used within typeahead are as follows:

const classNames = {
  wrapper: 'typeahead-standalone',  /* main container element */
  input: 'tt-input',
  hint: 'tt-hint',
  highlight: 'tt-highlight',
  list: 'tt-list',  /* container element for suggestions */
  hide: 'tt-hide',
  show: 'tt-show',
  selected: 'tt-selected',
  /* classes used within templates */
  header: 'tt-header',
  footer: 'tt-footer',
  loader: 'tt-loader',
  suggestion: 'tt-suggestion',
  group: 'tt-group',
  empty: 'tt-empty',
  notFound: 'tt-notFound',
};

As an example, if you want to use a different class name for the input element, you can initialize typeahead like this -

typeahead({
  input: '...',
  source: '...',
  classNames: {
    input: 'my-custom-input-class'  // this class is used instead of tt-input
  }
});

✨ API

typeahead.reset(clearLocalSrc?: boolean)

Resets the typeahead instance to the state it was in before any user interaction. It removes all items from the search index except those that were added via a local source. To remove absolutely all items, the function accepts an optional parameter which should be set to true. Reset() also clears cached remote requests.

const instance = typeahead({ /* options */ });
// clear search index except items added via Local source
instance.reset();

// clears entire search index
instance.reset(true);

This API is useful in situations where you need to invalidate data after a certain time has elasped.

typeahead.addToIndex()

Adds items to the search index. Useful when you want to fetch data yourself and then add it to the search index. It is similar to adding items via the Local source.

const instance = typeahead({ /* options */ });
instance.reset(true); // or instance.reset();
instance.addToIndex(['Blue, Baige , Black']);

typeahead.destroy()

Destroys the typeahead instance, clears search index, removes all event handlers and cleans up the DOM. Can be used if you wish to deactivate typeahead.

const instance = typeahead({ /* options */ });
instance.destroy();

💡 Error Codes

Here is a small glossary of the possible errors codes that one may come across

| Code | Description | | --------- | ----------- | | e01 | Missing input DOM element | | e02 | Missing/Incorrect source of suggestions. You must provide atleast one of the 3 possible sources - local, prefetch or remote with the expected source format (Ref) | | e03 | Missing Keys | | e04 | Prefetch request failed | | e05 | Remote request failed |


🧑‍💻 Contribute

Interested in contributing features and fixes?

Read more on contributing.

📝 Changelog

See the Changelog

📄 License

MIT © DigitalFortress