Git Product home page Git Product logo

popper.js.org's Introduction

Floating UI

Note

Popper is now Floating UI! For Popper v2, visit its dedicated branch and its documentation. For help on migrating, check out the Migration Guide.

Floating UI is a small library that helps you create "floating" elements such as tooltips, popovers, dropdowns, and more.

It offers two main features:

  1. Anchor positioning: Anchor a floating element (such as a tooltip) to another element (such as a button) while simultaneously ensuring it stays in view as best as possible by avoiding collisions. This feature is available for all platforms.
  2. User interactions for React: Hooks and components for composing interactions to create accessible floating UI components.

README Sponsors

Milford Dopt

You can sponsor Floating UI in a variety of ways on Open Collective.

Why

Floating elements are absolutely positioned, typically anchored to another UI element. Ensuring a floating element remains anchored next to another element can be challenging, especially in unique layout contexts like scrolling containers.

Absolute positioning can also cause problems when the floating element is too close to the edge of the viewport and becomes obscured, also known as a collision. When a collision occurs, the position must be adjusted to ensure the floating element remains visible.

Further, floating elements are often interactive, which can raise complex accessibility issues when designing user interactions.

Floating UI offers a set of low-level features to help you navigate these challenges and build accessible floating UI components.

Install

To install Floating UI, you can use a package manager like npm or a CDN. There are different versions available for different platforms.

Vanilla

Use on the web with vanilla JavaScript.

npm install @floating-ui/dom

You can either start by reading the tutorial, which teaches you how to use the library by building a basic tooltip, or you can jump right into the API documentation.

React

Use with React DOM or React Native.

React DOM

# Positioning + interactions
npm install @floating-ui/react

# Positioning only (smaller size)
npm install @floating-ui/react-dom

React Native

npm install @floating-ui/react-native

Vue

Use with Vue.

npm install @floating-ui/vue

Canvas or other platforms

If you're targeting a platform other than the vanilla DOM (web), React, or React Native, you can create your own Platform. This allows you to support things like Canvas/WebGL, or other platforms that can run JavaScript.

npm install @floating-ui/core

Contributing

This project is a monorepo written in TypeScript using pnpm workspaces. The website is using Next.js SSG and Tailwind CSS for styling.

  • Fork and clone the repo
  • Install dependencies in root directory with pnpm install
  • Build initial package dist files with pnpm run build

Testing grounds

DOM

pnpm run dev --filter @floating-ui/dom in the root will launch the @floating-ui/dom development visual tests at http://localhost:1234. The playground uses React to write each test route, bundled by Vite.

Each route has screenshots taken of the page by Playwright to ensure all the functionalities work as expected; this is an easy, reliable and high-level way of testing the positioning logic.

Below the main container are UI controls to turn on certain state and options. Every single combination of state is tested visually via the snapshots to cover as much as possible.

React

pnpm run dev --filter @floating-ui/react in the root will launch the @floating-ui/react development tests at http://localhost:1234.

Credits

The floating shapes in the banner image are made by the amazing artists @artstar3d, @killnicole and @liiiiiiii on Figma — check out their work!

License

MIT

popper.js.org's People

Contributors

aj-foster avatar armanio avatar atomiks avatar bulutfatih avatar dilyanpalauzov avatar fezvrasta avatar jdbruxelles avatar johannchopin avatar nclshart avatar piecyk avatar shrugsy avatar skvale avatar sun-2 avatar tmarshall avatar zeldocarina avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

popper.js.org's Issues

Overflowing popper

I'm using @popperjs/core version 2.5.3 to open my component under a dropdown. it works fine but when user opens the popper in small monitors the bottom of the popper will be cut off, so with detectOverflow() you can see the bottom of rect has a positive digit.
I want to open the popper in the middle of the screen so that the user can see the whole popper, I've spent a lot of time to figure out how to change the coordinate of the popper's rect to show it in the middle of the viewport but it seems there is no way to apply a computed coordinate base on the viewport to the popper that's just been opened. could you guide me a solution to address this issue?
thanks in advance.

Am I supposed to be able to read "Open Collective" on the popperjs homepage?

image

Steps to reproduce the problem

  1. Go to https://popper.js.org/
  2. Have adblocker enabled
  3. Attempt to read the text shown above

What is the expected behavior?

People are able to read the text

What went wrong?

People are not able to read the text

Any other comments?

Website: https://popper.js.org/

Full screenshot:
image

Yellow is #FFE69D Background is #FFE4E0

Screenshot from https://accessible-colors.com/:

image

Thank you in advance for looking into this.

I need to scroll to get correct position

Hi Guys,
I've created a popover component using the popper js, but always initial position is redering wrong. To fix the position i need to scroll so after to interect with the DOM the position change and become perfect.
I'm using classes, fade-in & fade-out to control the visibility follow below the classes.
The animations are using opacity to looks smoother.

&.fade-in { animation: fade-in 0.5s ease; visibility: visible; }
&.fade-out { animation: fade-out 0.5s ease; visibility: hidden; }

Before scroll:
image

After scroll:
image

Someone have faced it before or has some idea how to solve it?

Arrows gets twice position:absolute

https://popper.js.org/docs/v2/tutorial/#arrow suggests this call:

<div id="tooltip" role="tooltip">
  My tooltip
  <div id="arrow" data-popper-arrow></div>
</div>

and

#arrow,
#arrow::before {
  position: absolute;
  width: 8px;
  height: 8px;
  background: inherit;
}

As far as I can see, the arrow modified assigns the element with id="arrow" to state.elements.arrow. The appyStyles modifier sets state.elements.arrow.style.position='absolute'.

This means, that by following the tutorial the position style for the arrow-element is set twice to absolute: once using CSS and once by Javascript.

Please adjust either the tutorial, not to recommend setting explictly #arrow, #arrow::before { position: absolute }, or the arrow/applyStyle modifiers not to set for the arrow-element position: absolute.

E.g. the example shall set position: absolute for #arrow::before, but not for #arrow itself.

Moved from floating-ui/floating-ui#1528.

Popper js issue on mobile devices

I'm using Popper.js.org on my wordpress website http://3.97.176.72/locations. when you click view timings under locations, it show a pop up with some timings. It is working fine on laptop screen but when I switch to mobile device or tablet, I'm unable to click and view the popup. Is there any fix about it right now?

here is the code

View Timings

Mon:12:00 PM - 09:00 PM
Tue:12:00 PM - 09:00 PM
Wed:12:00 PM - 09:00 PM
Thu:12:00 PM - 09:00 PM
Fri:12:00 PM - 09:00 PM
Sat:12:00 PM - 09:00 PM
Sun:12:00 PM - 09:00 PM
<script>
  const button_mainstreet = document.querySelector('.button_mainstreet');
  const tooltip_mainstreet = document.querySelector('.tooltip_mainstreet');

  const popperInstance_mainstreet = Popper.createPopper(button_mainstreet, tooltip_mainstreet, {
    modifiers: [
      {
        name: 'offset',
        options: {
          offset: [10, 8],
        },
      },
    ],
  });

  function show_mainstreet() {
    // Make the tooltip_mainstreet visible
    tooltip_mainstreet.setAttribute('data-show', '');

    // Enable the event listeners
    popperInstance_mainstreet.setOptions((options) => ({
      ...options,
      modifiers: [
        ...options.modifiers,
        { name: 'eventListeners', enabled: true },
      ],
    }));

    // Update its position
    popperInstance_mainstreet.update();
  }

  function hide_mainstreet() {
    // Hide the tooltip
    tooltip_mainstreet.removeAttribute('data-show');

    // Disable the event listeners
    popperInstance_mainstreet.setOptions((options) => ({
      ...options,
      modifiers: [
        ...options.modifiers,
        { name: 'eventListeners', enabled: false },
      ],
    }));
  }

  const showEvents_mainstreet = ['mouseenter', 'focus'];
  const hideEvents_mainstreet = ['mouseleave', 'blur'];

  showEvents_mainstreet.forEach((event) => {
    button_mainstreet.addEventListener(event, show_mainstreet);
  });

  hideEvents_mainstreet.forEach((event) => {
    button_mainstreet.addEventListener(event, hide_mainstreet);
  });
</script>

it is really urgent as I've a demo tonight :)

[tutorial] Wrong popper position when initialized with display:none

CodeSandbox demo

https://codesandbox.io/s/react-popper-v2x-issue-template-forked-59dv1

Steps to reproduce the problem

Follow tutorial: https://popper.js.org/docs/v2/tutorial/#functionality

  1. Both reference and popper are inside of container with position: relative (this is a part of page layout). Without position: relative in ant parents an arrow will be positioned wrong.
  2. Popper initialized being display: none, similar to tutorial.
  3. User trigger an event, so a popper became display: block, similar to tutorial.

Tutorial lead you right to the bug which wouldn't be fixed (#413).

What is the expected behavior?

A popper positioned correctly. Tutorial helps you. Tutorial does explain or mention a problem with display: none positioning, and doesn't advice well-known buggy things without well-known solutions to workaround them.

What went wrong?

A popper position is wrong at first render. However if you resize viewport or scroll it, a popper will take correct position. You are trying to research what did you do wrong. Tutorial mess you.

Any other comments?

floating-ui/floating-ui#413 was found a time ago after a bug hitted. I suppose, I should to initialize a popper only after it becomes display: block and destroy when it becomes display: none. In theory it should to work.

@popperjs/core: 2.6.0

Memory leak in the tutorial example

Tutorial shows the example implementation and we can find there:

 show() {
   ...
  modifiers: [
                ...options.modifiers,
                { name: 'eventListeners', enabled: true }, 
            ]

options.modifiers is an array, so the above code keeps on adding new object at each call of show().

The same mistake is in hide() function.

You should change it to something like that:

function enableListeners(modifiers, value) {
   const modifier = modifiers.find((x) => x.name === 'eventListeners');
   if (!modifier) return [...modifiers, { name: 'eventListeners', enabled: open }];
   modifier.enabled = value;
   return modifiers;
}

show() {
   ...
   modifiers: enableListeners(options.modifiers, true)
   ...

Migration Issue with react-popper from v1 to v2 Causes Incorrect Button Positioning in Table

I am currently updating react-popper from version 1 to version 2 in my project. This migration has gone smoothly for the most part, except for an issue I've encountered when using popper in a table.

In the previous version, as I scrolled horizontally through the table, a button remained sticky at the end of the currently visible part of the table, with the translate3d value changing linearly as expected. However, in the migrated code, the button now appears at the absolute end of the table instead of being sticky. Additionally, the translate3d value behaves unexpectedly; it initially shows the correct value, but as soon as I scroll slightly to the left, it turns negative, which seems incorrect.

Previous V1 Code:

const PopperElement = memo(({ expanded, style, refProp, placement, update, isBucket, children }) => {
  // eslint-disable-next-line
  useEffect(() => update(), [expanded, isBucket])

  return (
    <div data-placement={placement} style={style} ref={refProp}>
      {children}
    </div>
  )
})

export const PopperContainer = memo(({ children, ...props }) => {
  const popperPlacement = props.mode === 'alerts' ? 'right-start' : 'left-start'

  return (
    <Popper placement={popperPlacement}>
      {({ placement, ref, style, scheduleUpdate }) => {
        return (
          <PopperElement
            placement={placement}
            style={{ zIndex: 8, ...style }}
            refProp={ref}
            isBucket={props.isBucket}
            expanded={R.prop('expanded', props)}
            update={scheduleUpdate}
          >
            {children}
          </PopperElement>
        )
      }}
    </Popper>
  )
})

Migrated Version 2 Code:

export const PopperContainer = memo(
  ({ children, referenceElement, popperElement, setPopperElement, ...props }) => {
    const popperPlacement = props.mode === 'alerts' ? 'right-start' : 'left-start'

    const { styles, attributes, update } = usePopper(referenceElement, popperElement, {
      placement: popperPlacement,
      modifiers: [
        {
          name: 'adaptive',
          enabled: false
        }
      ]
    })

    const expanded = R.prop('expanded', props)
    useEffect(() => {
      if (update) {
        console.log('here update')
        update()
      }
    }, [expanded, props.isBucket, update])

    return (
      <div ref={setPopperElement} style={{ ...styles.popper, zIndex: 8 }} {...attributes.popper}>
        {children}
      </div>
    )
  }
)

I've tried to adjust the styling to force the correct behavior:

    // eslint-disable-next-line no-unused-vars
    const { left, top, bottom, right, ...restStyles } = styles.popper
    restStyles.willChange = 'transform'
    restStyles.left = 0
    restStyles.top = 0
    restStyles.position = 'absolute'

In the previous implementation using react-popper v1, the button maintained a sticky position at the end of the current visible portion of the table during horizontal scrolling, with the translate3d value updating linearly in a predictable manner.

After migrating to react-popper v2, the button no longer behaves as expected. Instead of maintaining its position relative to the viewport, it is now positioned at the absolute end of the table. Additionally, the translate3d values exhibit unexpected behavior: they start with the very end(with current value), but as soon as I begin to scroll left, the values rapidly shift to negative numbers, which is not the intended behavior and seems incorrect.

React popper example fo react classes

First of all, thank you for open-sourcing such a wonderful library.

On the page https://popper.js.org/react-popper/v2/react-portals/

As a user using reactjs using classes, I am unable put the example provided, in my context. I am seeing useState and useEffect everywhere and I don't know who it will fit for me in react classes.

Please add an example (if possible) showing how to use react-popper in react classes. Thank you :)

Navigation broken

Screen Shot 2021-02-27 at 11 40 35 am

Navigate to the next pages using these buttons and after the first load, it will only display "Home".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.