Wondering what’s next for npm?Check out our public roadmap! »

    filter-suggest

    3.5.5 • Public • Published

    FilterSuggest

    A react component for achieving search-as-you-type functionality on a list of option items. The actual sorting & filtering of items is left up to you, making it easy to combine data from multiple sources (synchronous & asynchronous).

    Implemented using downshift and material-components-web-react.

    Travis npm package Coveralls

    Demo

    https://dan-kwiat.github.io/filter-suggest

    Installation

    With Yarn:

    yarn add filter-suggest
    

    Or npm:

    npm install --save filter-suggest
    

    You'll need to have the peer dependencies installed too:

    {
      "prop-types": "15.x",
      "react": "16.x"
    },

    Examples

    Sync

    A basic synchronous example using match-sorter to sort items:

    import React, { useState } from 'react'
    import FilterSuggest from 'filter-suggest'
    import 'filter-suggest/es/index.css'
    import matchSorter from 'match-sorter'
     
    const ITEMS = [
      {
        id: `movie-1`,
        icon: null,
        primary: 'movie:The Big Short',
        secondary: 'Filter by movie',
      },
      // add more items here
    ]
     
    const Demo = () => {
      const [inputValue, setInputValue] = useState('')
      const sortedItems = inputValue ? matchSorter(
        ITEMS,
        inputValue,
        { keys: ['primary'] }
      ) : []
      return (
        <FilterSuggest
          inputValue={inputValue}
          label='Start typing...'
          onInputValueChange={setInputValue}
          onSelect={item => {
            // deal with selected item here
          }}
          items={sortedItems}
        />
      )
    }

    See the demo source code for a more comprehensive synchronous example.

    Async

    A basic asynchronous example using a dummy GraphQL endpoint to fetch sorted items:

    import React, { Component } from 'react'
    import debounce from 'lodash.debounce'
    import gql from 'graphql-tag'
    import { Query } from 'react-apollo'
    import FilterSuggest from 'filter-suggest'
    import 'filter-suggest/es/index.css'
     
    const DEBOUNCE_TIME = 100
    const applyDebounced = debounce((f, x) => f(x), DEBOUNCE_TIME)
     
    const QUERY = gql`
      query GET_ITEMS(
        $search: String!
      ) {
        getItems(
          search: $search
        ) {
          id
          primary
          secondary
        }
      }
    `
     
    class AsyncDemo extends Component {
      state = {
        inputValue: '',
        variables: {
          search: '',
        }
      }
      setInputValue = inputValue => {
        this.setState({ inputValue })
      }
      setVariables = variables => {
        this.setState({ variables })
      }
      onInputValueChange = value => {
        this.setInputValue(value)
        applyDebounced(this.setVariables, { search: value })
      }
      render() {
        const { inputValue, variables } = this.state
        return (
          <Query query={QUERY} variables={variables}>
            {({ data, loading, error }) => {
              return (
                <FilterSuggest
                  inputValue={inputValue}
                  label='Search async'
                  loading={loading}
                  onInputValueChange={this.onInputValueChange}
                  onSelect={item => {
                    // handle selected item
                  }}
                  items={inputValue && data ? data.getItems : []}
                />
              )
            }}
          </Query>
        )
      }
    }

    For a seamless search-as-you-type experience, results should be returned very quickly (say of the order 100ms). You might want to look at Elasticsearch completion suggester or PostgreSQL trigram indices.

    See charity-base-search for a real-world asynchronous example.

    Props

    FilterSuggest accepts the following props:

    FilterSuggest.propTypes = {
      // Optional class applied to the parent div
      className: PropTypes.string,
      // Error message to render instead of dropdown
      errorMessage: PropTypes.string,
      // The current value of the input (you must handle the state yourself)
      inputValue: PropTypes.string.isRequired,
      // An array of items to render in the dropdown
      items: PropTypes.arrayOf(PropTypes.shape({
        // A unique item id
        id: PropTypes.string.isRequired,
        // An optional icon to render on the left
        icon: PropTypes.element,
        // The main text to display on the item
        primary: PropTypes.string.isRequired,
        // Secondary text to display below the main text (useful for giving prompts)
        secondary: PropTypes.string,
        // You may want to provide additional item props here (for use in the onSelect callback)
      })).isRequired,
      // The input label
      label: PropTypes.string,
      // Optional icon element to prefix the input
      leadingIcon: PropTypes.element,
      // Whether or not the items are loading
      loading: PropTypes.bool,
      // Maximum number of items to render in dropdown list
      maxSuggestions: PropTypes.number,
      // Optional class applied to the dropdown menu
      menuClassName: PropTypes.string,
      // Blur event handler
      onBlur: PropTypes.func,
      // Focus event handler
      onFocus: PropTypes.func,
      // A callback fired whenever an input value change is detected
      onInputValueChange: PropTypes.func.isRequired,
      // A callback fired whenever an item is selected
      onSelect: PropTypes.func.isRequired,
      // Whether or not to render the outlined variant of text field
      outlined: PropTypes.bool,
      // Optional class applied to the input element's parent
      textFieldClassName: PropTypes.string,
    }
    FilterSuggest.defaultProps = {
      label: 'Start typing...',
      maxSuggestions: 12,
    }

    Styles

    With CSS:

    import 'filter-suggest/es/index.css'

    With Sass:

    import 'filter-suggest/es/index.scss'

    The colour theme can be customised using the following Sass mixin:

    $mdc-theme-primary: #00ff00;

    For further customisation see MDC Web's mixins for the text field and list.

    You may also supply textFieldClassName and menuClassName props which will be applied to the appropriate components.

    Install

    npm i filter-suggest

    DownloadsWeekly Downloads

    12

    Version

    3.5.5

    License

    MIT

    Unpacked Size

    26.9 kB

    Total Files

    11

    Last publish

    Collaborators

    • avatar