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

react-nested-popper

v1.1.0

Published

A react library based on popper.js that supports nested poppers and proper context binding.

Downloads

3,699

Readme

react-nested-popper

npm version MIT license

Demos here: https://runfaj.github.io/react-nested-popper/

What

react-nested-popper is a react library based on V2 popper.js, but with added features created to handle a number of popper scenarios that other libraries fail to capture:

  • handling for nesting and popper groups, combined with outside clicks
  • proper handling for context with nested popper content
  • full implementation of popper.js allowing all popper options
  • support for portals to decouple the popper content

This library is an unstyled, functionality-only library.

Why

We used react-popper for a long time and have liked it. However, we kept finding that there were situations where we couldn't do things because of the need for stackd nested poppers and the inability to upgrade some of our packages. We've tried other similar libraries, but none met our needs. Once popper.js V2 came out, the decision was made to put in the effort to make our own popper library. So...here we are!

Installation

Install the Package: npm install react-nested-popper or yarn add react-nested-popper

Add to your jsx file:

import { Popper, Target, Content } from 'react-nested-popper';

// render
<Popper>
  <Target>{/* The target that the popper is tied to here */}</Target>
  <Content>{/* The content to appear in the popper here */}</Content>
</Popper>

Note 1: The Popper must always have 1 Target and 1 Content
Note 2: react and react-dom are required peer dependencies

Options

The react-nested-popper is created firstly to handle multiple nested poppers. This is achieved by a "stack". By default, all popper instances will determine their own stack, but you can create your own stacks as needed.

In addition, you can create a controlled popper (the hide/show state is managed by you), or an uncontrolled popper (the hide/show state is managed by the library).

With that in mind, here's the options available for the three components:

Popper


Target


Content


Stack


You can also manually use the Stack util, should you need. Here's the public methods:

groupName

<Popper
  (default case: groupName="auto")
  (or)
  groupName="string"
  (or)
  groupName={["string", "string"]}
>

The group name for popper is a bit complicated, so merits some explanation.

The group name on a popper specifies which group(s) a set of poppers belongs to. For example, if you wanted to have two poppers open at the same time, but then close in the order you opened them, you could specify each popper to belong to the same group. Alternately, you could have two poppers open at the same time and close at the same time with different groups.

This is also useful for nesting, as nesting poppers and putting them in the same group will only close the top most item in the group when clicking outside. The opposite with different groups might be dropdowns where only one should be open at a given time.

With all of these cases, please see the demos to visually see how the group name affects nesting. First we'll look at custom group names, then the default "auto" case.

Single group

You can define the groupName as any string you'd like (except "auto"). For example, here's a "global" group:

<Popper
  groupName="global"
>

Depending on the need, you may need to have a set of poppers belong to a different group though. For example, maybe you want multiple popovers to open independent of each other.

<Popper
  groupName="popper1"
>
<Popper
  groupName="popper2"
>

If you define multiple poppers as the same group (regardless of physically nested or not), they will close in the opposite order they were opened.

<Popper
  groupName="global"
>
<Popper
  groupName="global"
>

Multiple groups

Sometimes, a single group name for poppers isn't enough, like having a nested popper, but each nested item should toggle from other items. What does this mean? Let's look at a specific example.

Say I made a component that was a popper with a form inside. On this form were two dropdowns, each being their own popper component. In this situation, I might want to keep the parent popper open, but only allow one child dropdown to be open at a time.

We can't accomplish this with just one group because the dropdowns need to have separate groups to only allow one to be open. But, they both need to belong to the parent popper group. So, that's where multiple group names are needed.

<Popper
  groupName="popper"
>
  <Dropdown
    groupName={["popper", "dropdown1"]}
  >
  <Dropdown
    groupName={["popper", "dropdown2"]}
  >
</Popper>

The array of group names is arranged from lowest to highest group, so in this case, the lowest open item would be the popper group, then the dropdown group.

Default "auto" case

By default, groupName will be "auto". This means that the nesting will try to determine stacks by itself. With auto, the functionality behaves as follows:

  1. If no other popper is open, create a new stack and add this popper to it.
  2. If another popper is open, look to see if the target for this popper belongs to the open popper:
    • If doesn't belong to another popper, add to new stack.
    • If belongs to another popper:
      1. find the parent popper in the stack.
      2. Move any poppers that are children of the parent to a new stack
      3. Add the new popper to the same stack as the parent.

To interpret these rules, we basically do somemthing similar to the example mentioned in the Multiple Groups above, but automatically determine the group names so you don't have to.

How groupName actually works

This is the main point of this package. Basically, when a popper belongs to a group, we create a stack of poppers that belong to the given groups defined for each popper. We use this stack to track the last opened item and only close the last opened item in the group.

With multiple groups, we treat the multiple groups as a mini-stack as well, where we only close the last item of the list of groups where a group contains an item. Confused yet? Anyway, this approach allows for binding multiple groups while only closing the top most item as needed each time.

Misc

This package is published under the MIT License.

Thanks to:

  • Grow.com, for the amazing place to work and build software
  • robskidmore, for helping plan out this package
  • runfaj, for creating this package
  • All contributors (code, issues, documentation, etc.) for helping make this package continually better

FAQ

  • What's with all the weird dependencies? Nearly all the dependencies listed are for the demo. The webpack bundle splits out to where the only things that are actually used in this package are a couple lodash methods and the popperjs library. react and react-dom are not included as they are peer dependencies.