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

@oshq/react-select

v1.4.2

Published

The React Select is a minimal select component for reactjs.

Downloads

86

Readme

React Select

The React Select is a minimal select component for reactjs.

Table of Content

Installation

You can install the React Select component via npm:

npm i @oshq/react-select

Usage

Basic Implementation

import Select from '@oshq/react-select';
import '@oshq/react-select/index.css';

const App = () => {
  const [selected, setSelected] = useState(undefined);
  const options = [
    { label: 'apple', value: 'apple' },
    { label: 'ball', value: 'ball' },
    { label: 'cat', value: 'cat' },
    { label: 'dog', value: 'dog' },
  ];
  return (
    <Select
      value={selected}
      onChange={(_,val) => {
        setSelected(val);
      }}
      options={async () => options}
    />
  );
};

Examples

MultiSelect

const App = () => {
  const [selected, setSelected] = useState(undefined);
  const options = [
    { label: "apple", value: "apple" },
    { label: "ball", value: "ball" },
    { label: "cat", value: "cat" },
    { label: "dog", value: "dog" },
  ];
  return (
    <Select
      multiple
      value={selected}
      onChange={(_,val) => {
        setSelected(val);
      }}
      options={async () => options}
    />
  );
};

Grouped

const App = () => {
  const [selected, setSelected] = useState(undefined);
  const options = [
    {
      label: "Fruits",
      options: [
        { label: "Apple", value: "apple" },
        { label: "Mango", value: "mango" },
      ],
    },
    {
      label: "Vegetables",
      options: [
        { label: "Potato", value: "potato" },
        { label: "Pumpkin", value: "pumpkin" },
      ],
    },
    {
      label: "Cereal",
      options: [
        { label: "Maize", value: "maize" },
        { label: "rice", value: "rice" },
        { label: "Wheat", value: "wheat" },
      ],
    },
  ];
  return (
    <Select
      value={selected}
      onChange={(_,val) => {
        setSelected(val);
      }}
      options={async () => options}
    />
  );
};

Searchable

const App = () => {
  const [selected, setSelected] = useState(undefined);
  const options = [
    { label: 'apple', value: 'apple' },
    { label: 'ball', value: 'ball' },
    { label: 'cat', value: 'cat' },
    { label: 'dog', value: 'dog' },
  ];
  return (
    <Select
      searchable
      value={selected}
      onChange={(_,val) => {
        setSelected(val);
      }}
      options={async () => options}
    />
  );
};

Creatable

const App = () => {
  const [selected, setSelected] = useState(undefined);
  const options = [
    { label: "apple", value: "apple" },
    { label: "ball", value: "ball" },
    { label: "cat", value: "cat" },
    { label: "dog", value: "dog" },
  ];
  return (
    <Select
      creatable
      multiple
      value={selected}
      onChange={(_,val) => {
        setSelected(val);
      }}
      options={async () => options}
    />
  );
};

Asynchronous

const App = () => {
  const [selected, setSelected] = useState(undefined);
  const options = async () => {
    const data = await (
      await fetch("fetch_api")
    ).json();
    return [...data.map((res) => ({ label: res.title, value: res.id }))];
  };

  return (
    <Select
      searchable
      value={selected}
      onChange={(_,val) => {
        setSelected(val);
      }}
      options={options}
    />
  );
};

Customization

const App = () => {
  const [selected, setSelected] = useState([]);
  const options = [
    { label: "apple", value: "apple" },
    { label: "ball", value: "ball" },
    { label: "cat", value: "cat" },
    { label: "dog", value: "dog" },
  ];

  const closeIcon = () => {
    return (
      <svg
        width="12"
        height="12"
        strokeWidth="2"
        xmlns="http://www.w3.org/2000/svg"
        fill="none"
        viewBox="0 0 32 32"
      >
        <path
          stroke="currentColor"
          strokeLinecap="round"
          strokeLinejoin="round"
          strokeWidth="2"
          d="M24 8 8 24M24 24 8 8"
        />
      </svg>
    );
  };

  const chevronDown = () => {
    return (
      <svg
        width="12"
        height="12"
        strokeWidth="2"
        xmlns="http://www.w3.org/2000/svg"
        fill="none"
        viewBox="0 0 32 32"
      >
        <path
          stroke="currentColor"
          strokeLinecap="round"
          strokeLinejoin="round"
          strokeWidth="2"
          d="M26 11 16 21 6 11"
        />
      </svg>
    );
  };

  return (
    <Select
      showclear
      multiple
      value={selected}
      onChange={(_,val) => {
        setSelected(val);
      }}
      options={async ()=> options}
      
      placeholder={<div className="text-white/50">Customize</div>}
      
      className={() => {
        const custom =
          "bg-black text-sm text-white px-2 py-0.5 border-solid font-sans border rounded min-w-[50px] outline-none";
        return {
          default: `${custom} border-stone-200`,
          focus: `${custom} border-stone-200 ring-1 ring-orange-400`,
          disabled: `${custom} text-black/25 bg-black/5 border-stone-100`,
        };
      }}
      
      suffixRender={({ clear, showclear }) => {
        return (
          <div className="flex flex-row items-center gap-1 px-2">
            {showclear && selected && selected?.length > 0 && (
              <span className="cursor-pointer hover:opacity-60" onClick={clear}>
                {closeIcon()}
              </span>
            )}
            <span>{chevronDown()}</span>
          </div>
        );
      }}
      
      tagRender={({ label, remove, value }) => {
        return (
          <div className="bg-yellow-600 rounded px-1.5 truncate py-0.5 flex flex-row items-center justify-center gap-2">
            <span className="truncate">{label}</span>
            <span
              className="cursor-pointer hover:opacity-60"
              onClick={() => remove(value)}
            >
              {closeIcon()}
            </span>
          </div>
        );
      }}
      
      menuClass="bg-yellow-600 p-1 rounded shadow-2xl"
      
      menuItemRender={({ label, innerProps, active, focused }) => {
        return (
          <div className="py-px truncate" {...innerProps}>
            <div
              className={cn("py-2 px-1 rounded truncate", {
                "bg-yellow-500": !!active,
                "bg-yellow-400": !!focused && !active,
              })}
            >
              {label}
            </div>
          </div>
        );
      }}
    />
  );
};

Dealing with extra data

If you're handling additional data, React Select seamlessly supports it out of the box. Simply include your data alongside { label, value, ....your_extra_data_here } for each item. For instance, consider the following example where countryis included as extra data. This supplementary information can also be accessed upon triggering the onChange event.

const countries = async () => {
  const data = await (
    await fetch(
      'https://cdn.jsdelivr.net/npm/[email protected]/dist/index.json'
    )
  ).json();

  return [
    ...data.map((country) => ({
      label: `${country.name}`,
      value: `${country.code}`,
      render: () => (
        <div className="flex flex-row items-center gap-1 truncate">
          <span>{country.emoji}</span>
          <span className="truncate">{country.name}</span>
        </div>
      ),
      country,
    })),
  ];
};

const App = () => {
  const [selected, setSelected] = useState(undefined);

  return (
    <Select
      value={selected}
      onChange={(_,val) => {
        setSelected(val);
      }}
      options={countries}
      valueRender={(value) => (
        <div className="flex flex-row items-center gap-1">
          <span>{value.country.emoji}</span>
          <span>{value.label}</span>
        </div>
      )}
    />
  );
};

The render function

You have the option to include a render function alongside your items. Take this JSX snippet, for instance:

{
  label: "Hello world",
  value: "hello",
  render: ({ active, focused }) => <div>Hello world</div>,
}

This feature empowers you to tailor each option item according to your preferences.

Props

options

  • Type: async () => [....]
  • Description: Asynchronously retrieves selectable options for the Select component. Expects a function returning a Promise resolving to an array of objects representing options or a complex structure for grouped options, including labels and values.

value

  • Type: string | string[]
  • Description: Represents the current value(s) of the Select component. It should be string or array of string.

virtual?

  • Type: boolean
  • Default: true
  • Description: Enables optimized rendering for handling large sets of options efficiently through virtual scrolling. Helps in rendering only visible options, improving performance.

noOptionMessage?

  • Type: ReactNode
  • Description: Customizable message or ReactNode to display when no options are available within the Select component.

disableWhileLoading?

  • Type: boolean
  • Default: false
  • Description: Disables the Select component while asynchronously fetching options to prevent interaction until options are loaded.

placeholder?

  • Type: ReactNode
  • Description: Placeholder text or ReactNode displayed when no option is selected.

multiple?

  • Type: boolean
  • Default: false
  • Description: Determines whether the Select component allows multiple options to be selected.

open?

  • Type: boolean | undefined
  • Default: false
  • Description: Controls the visibility of the dropdown menu.

disabled?

  • Type: boolean
  • Default: false
  • Description: Disables the Select component when set to true.

searchable?

  • Type: boolean
  • Default: true
  • Description: Enables a search feature within the Select component to quickly find options.

creatable?

  • Type: boolean
  • Default: false
  • Description: Enables users to create new options within the Select component.

showclear?

  • Type: boolean
  • Default: false
  • Description: Displays a clear button for removing selected value(s).

suffixRender?

  • Type: (value: ISuffixRender) => ReactNode
  • Description: Allows customizing the appearance of the suffix area in the Select component.

groupRender?

  • Type: (value: IGroupRender) => ReactNode
  • Description: Enables custom rendering styles for group label.

tagRender?

  • Type: (value: ITagRender) => ReactNode
  • Description: Customizes the rendering style for selected tags, in multi-selection scenarios.

menuItemRender?

  • Type: (value: IMenuItemRender) => ReactNode
  • Description: Facilitates customization of individual menu item's renderings.

valueRender?

  • Type: (value: type_of_item) => ReactNode
  • Description: Customizes the rendering style for selected value in input field.

className?

  • Type: string | (() => { focus?: string; disabled?: string; default?: string })
  • Description: CSS classes for customizing select input field.

portalClass?

  • Type: string
  • Description: CSS classes for the portal element.

menuClass?

  • Type: string
  • Description: CSS classes for the dropdown menu container of the Select component.

animation?

  • Type: null | AnimationProps(FramerMotion animation props)
  • Description: Configures animations for the dropdown menu. When set null, disables the animation.

onChange?

  • Type: (value:object, valueAsString:string) => void
  • Description: Triggered upon changes to the selected value(s).

onOpenChange?

  • Type: (open: boolean) => void
  • Description: Triggered when the dropdown menu opens or closes.

onSearch?

  • Type: (text: string) => void | boolean
  • Description: Triggers when typing. If true or void is returned then it uses in-build filtering.

Types

type ISuffixRender = {  
	showclear?:  boolean  |  undefined;  
	clear?: (() =>  void) |  undefined;  
	isOpen?:  boolean  |  undefined;  
	loading?:  boolean  |  undefined;  
}

type IGroupRender = {  
	label:  string;  
}

type ITagRender = {  
	remove: (value:  string) =>  void;  
	value:  string;  
	label:  string;  
}

type IOptionRender = string | (({ active, focused }: { active: boolean; focused: boolean }) => ReactNode);

type IMenuItemRender = {  
	active?:  boolean  |  undefined;  
	focused?:  boolean  |  undefined;  
	label:  string;  
	value:  string;  
	render: IOptionRender;  
	innerProps?: { ... } |  undefined;  
}