-
Notifications
You must be signed in to change notification settings - Fork 24
Change positioning engine library: Migrate from react-tether to react-popper (Proposal) #217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Great job writing this RFC! I believe it makes a lot of sense to make this change. |
FWIW I recommend using Floating UI's new React DOM package: https://floating-ui.com/docs/react-dom Read more about the change: https://floating-ui.com/docs/motivation |
Thank you very much @JanHamara this is an amazing RFC, and the proposal looks good and makes sense. Agree with @martimalek. I believe this should not add any breaking change in the two affected components so we should be able to proceed with the migration without any issue. |
Thanks @atomiks for sharing. It looks very interesting we might open a spike and consider the library for the change. |
Hello @atomiks, thank you very much for your comment and insight! I would just have a couple of questions about what you've said and recommended :) Could you please clarify what repository/project you refer to, when you mention ''react-popper not undergoing active development at this current time'' ?The module that this RFC talks about and proposes using is part of Floating UI and it's floating-ui/react-popper and it seems to be maintained as described in RFC, with latest release 4 days ago bringing support for React 18 (idk if by active development you meant new features, or we were referring to different libraries). On the other side, the https://floating-ui.com/docs/react-dom seems to be still using ReactDOM.render method, instead of the new createRoot method from react-dom/client. From this I would assume that it's not migrated to use React 18 features yet. To be honest, I feel like I am a little bit confused as to which of these two is the ''latest solution'' or the best solution, as the one we've introduced in this RFC seems to be part of Floating UI + ready for React 18, while the one you have suggested seems not yet. Also this article that mentions your contribution: https://opencollective.com/floating-ui/updates/popper-is-evolving-into-floating-ui talks about new @floating-ui/popper library, for which I believed floating-ui/react-popper would be the official React wrapper for (as due to the description on repo)... Is that also the same library with different name, or something that is in plan for the future? As there is clearly need for more clarity on our side, could you please explain to us the differences and relations between these? 1. floating-ui/react-dom 2. floating-ui/react-popper + why we should consider using floating-ui/react-dom over floating-ui/react-popper? We currently have implementation with desired behaviour done with floating-ui/react-popper and we're wondering what would be the main additional benefits from making the proposed change to floating-ui/react-dom :) Are we supposed to understand your previous comment in a way that floating-ui/react-popper will be deprecated / not maintained anymore? Thank you very much again! |
Yes the
I'm not sure where you're seeing this, but it does not use
The Motivation page linked explains why Floating UI over Popper. The React libraries are just wrappers over each, but I think the confusion here is that TL;DR, use https://floating-ui.com/docs/react-dom.
|
@JanHamara in the link you posted for floating-ui/react-popper there is a message in the README stating that the library is in maintenance mode (I don't know how I missed it before 😅). Also I can see that @floating-ui/react-dom is supporting React 18. Maybe it would be worth trying to implement the Popover with @floating-ui/react-dom before making a decision. |
https://codesandbox.io/s/quizzical-water-b3dedw?file=/src/index.tsx Right, I was looking at examples from the Docs page on non-dialog popover (link above) and seen it was still using render method from react-dom, that's where the confusion came from. Okay, we will go ahead and test an implementation with @floating-ui/react-dom, then 👍 |
I apologize in advance for quite a lengthy post! UPDATEAfter spending quite some time trying to implement the Popover component with our desired behaviour with @floating-ui/react-dom, and consulting the learnings with other participants on this thread, we have decided to go with @react-popper. Following is the reasoning behind this decision: Before listing reasons, why I think we should stick with @react-popper for now, I just want to state that @floating-ui is definitely a really interesting project and may be our go-to library in the future, however, due to our current needs and the following drawbacks of the lib, going with a @react-popper implementation is better for us at the moment: 1. Unnecessary complexity for our current needs@floating-ui is a low-level library that aims to give you a completely fine-grained granular control over the anchored positioning and repositioning behaviour of whatever floating element you are building (be it tooltip, popover or modal, etc.), that includes detecting the overflow when resizing window or scrolling, updating the position of the floating element, flipping or shifting the element when needed, etc. (also showing / hiding the floating element with libs hooks for user interactions - only for React). That means none of this is enabled by default. As react-dom docs state, @floating-ui/react-dom useFloating() hook only calculates the position once on render, or when the reference/floating elements changed — for example, the floating element gets mounted via conditional rendering. If the floating element lives in a different offsetParent context to the reference element, it will need to be updated while mounted to remain “anchored”. This includes scrolling and resizing the window or the elements themselves. We need to configure the updating of floating element's position ourselves with autoUpdate method, and this is where confusion begins (after clicking the link to go to autoUpdate docs), but about this in next points... To stay at the initial point first, we don’t need such a low-level granular library at the moment, as we don’t need an overly complicated solution where we would want to specify in detail the whole repositioning behaviour, we need a simpler out-of-the-box solution with a lib, that will take care of rendering the Popover content, automatically detecting the overflow on window.resize and on scroll, and repositioning (update, flip, shift) the Popover content as needed, something that we can implement quickly and it works. @floating-ui docs even recommend this in the Tutorial part: Note: I would like to note here @atomiks , that this second paragraph is quite misleading. You recommend to use MUI, ChakraUI, etc. as ''All of the mentioned libraries use this library (formerly, Popper) under the hood.'' Reading ''use this library (formerly Popper)'' on @floating-ui documentation site, it quite clearly implies that they use @floating-ui under the hood, while in fact none of them use @floating-ui, they also still depend on @popperjs/core. MUI - Source Anyways, @react-popper enables the repositioning modifiers by default and takes care of detecting when we are scrolling or window resizes, repositioning the Popover content automatically if it cannot fit into viewport in its current position. We can achieve this in no time with the basic working example in the documentation, allowing us to focus on what is important (whether that is building the different variants we need, focusing on styling or simply not spending too much time on the implementation of this component) With @floating-ui it was not so easy, and this brings me to second point... 2. It's not quite ready for production yet - Documentation is not clear, at times even confusing and currently too unstable, it mutates almost on daily basis...I think, the reasons why some top component libraries (like Chakra UI, Bootstrap, MUI, etc.) are not yet using @floating-ui library (even thought it’s a great project) are:
Without writing too much and boring you, I will try to explain how it may be confusing: The docs begin with a pretty clear intro of the library concept and introduction of various packages / solutions (Native, React, React Native, Canvas)... However, first page refers you to go straight to react-dom docs (if you’re developing React component) - this automatically assumes you already know / passed the concepts from Tutorial / computePositions chapter and not expect that all necessary concepts that you need to know for React implementation would indeed be in React part of documentation... But anyways, let's assume we go through them anyways, mainly Tutorial which teaches you how to build a Tooltip with Native JS solution, which is completely different than solution you would have with React. I understand it may be just simpler to explain lib concepts with simplest solution, but this tutorial also introduces important utilities for React solutions such as autoUpdate, in different context, which already brings confusion about how this would be used in React solution (considering all lifecycle methods, etc.) For example, say we start following steps in react-dom docs and we get to the part where we need to set up autoUpdate so we click the link to go to its documentation page: Therefore, we move on to read autoUpdate docs page as we need to update the position automatically, but wait, this page again explains how to use this method with computePosition method, and autoUpdate method imported from floating-ui/dom package. But react-dom docs page has already told me to import useFloating wrapper hook and autoUpdate method from floating-ui/react-dom package. This brings a lot of confusion and questions:
Anyways, this is just an example to make a point, but I feel like the main issue would be to have the confidence we are using a stable solution when the documentation currently changes almost on daily basis. One more example to demonstrate this: whileElementsMounted, ‘’fully reactive callback prop to handle mounting/unmounting of the elements.’’ which we are told to use in conjunction with autoUpdate method for updating the position has only been added 9 days ago. → Commit #e52eea7 3. Lack of demo / working examples that would demonstrate implementation of a basic solution for react-domAs also mentioned here: floating-ui/floating-ui#1677 There is no single clear and concise guide for developing a basic solution with React that would detect overflow and / or scrolling, and reposition (flip, shift) floating element when it cannot fit into the viewport. For example, it would be extremely helpful to have demos of integration with react-dom solution, for the examples that you present on landing page. Yes, there are examples on react-dom-interactions page, but they demonstrate yet another solution using react-dom-interactions, while we are being told to use @floating-ui/react-dom with React DOM (especially if we don't need to incorporate custom logic). I undestand what you are trying to say here: However, I think many teams will want to use your library as future-proof solution (as it obviously will bring many amazing advantages like minimal size, cross-platform compatibility, improved extensibility) for simple use-cases of Popover, Modal, Tooltip, etc. without ''having to reinvent the wheel'' 4. Element position doesn't get computed when rescaling in iframeMaking it currently not possible to use other tools that depend on it, like Storybook, for development/testing/documentation of Popover component. 5. We are not at v1 yet, it is not being used by many dependantsUmbrella - Roadmap to Floating UI v1 If we look at break down of dependents of popper.js and floating-ui/react-dom under @floating-ui repo, at the moment we can see: popper.js: 2.1 million dependants ConclusionWe are fully aware that popper.js will become obsolete over longer period of time. We also believe @floating-ui is a cool project and surely will be a go-to library for devs who want to have granular control over every single piece of positioning behaviour of floating element, but at this moment the lib and documentation mutate too often and are too unstable to be used for our Popover integration. We will keep monitoring this library and when we see v1 released and / or some big players start using it, we will definitely reconsider moving to it. Thank you for your insights @atomiks and we will be hoping to see v1 soon 👍 |
@JanHamara thank you for the feedback especially regarding the docs. I keep trying to improve the docs to be better worded but unfortunately it seems it is still confusing. But your feedback was very valuable, thanks 👍 So to your points: it sounds like most of your concern is the library not being v1 yet and the documentation not being clear enough. Let me try to address these: 1.. It's not that complex, if you want to replicate Popper's "out of the box" behavior, all it takes is this: import {useFloating, flip, shift, autoUpdate} from '@floating-ui/react-dom';
useFloating({
middleware: [flip(), shift()],
whileElementsMounted: autoUpdate,
}); The reason most of those libraries have not updated yet is because they can't update quickly at all. It takes a long time for them to move to the new dependency due to the breaking API changes. Further, this "out of the box" behavior is inherently misleading because it still doesn't handle every single case. Popper is completely missing the 2.. This is largely because it's in v0. It's been in v0 to gather feedback on the new API but most of the breaking changes are small and can be updated in a couple lines or two by reading the changelog in releases section. I want to release v1 by the beginning of next month. The documentation is mainly changing not because APIs change but to help improve the wording. The The changes are largely adding and improving things, not breaking them. e.g. Popper also suffered from these issues, it only provided out of the box behavior to simplify it but you still needed to read the vanilla modifiers docs to configure things. So it's basically the same imo. 3.. The API is designed to be less hard to adjust and more predictable. For instance, you start with simple anchored positioning and then add "visibility optimizations" through middleware afterward. This results in smaller bundles. Plus you don't need to write out a bunch of 4.. Popper also has this bug. It's not severe and almost no one will encounter it, as evidenced by it being a new bug and Popper also having it the whole time. The concern about iframes is not an issue because the element is outside of the iframe, plus it's scaled, the combo is extremely rare. 5.. popper.js is for v1, the v2 dependents are not listed. But yeah, obviously it has way more as it's existed for much longer 😄 To be honest I do think it's a mistake to use Popper in new projects if you are starting fresh. Popper is larger, has less features (especially There are a bunch of bugs in Popper that have been fixed in Floating UI that you may encounter using it. Plus, it's about to hit v1 very soon and your concerns about it not being stable won't be an issue soon. Popper is only stable because it's missing a ton of features and wasn't being actively developed as its non-treeshakeable architecture prevented that. So while it may look unstable because there is lots of activity on it, it is actually very stable and less buggy than Popper and only minor API changes are occurring. Plus new features, etc. Another thing is Popper has poor TS support. There's zero autocomplete for the modifiers configuration. Floating UI is written in TS and has first class support |
I'm closing this issue because the decision is taken. We will keep watching |
Change positioning engine library: Migrate from react-tether to react-popper (Proposal)
This proposal comes up as a result of the integration process of the new Popover component and realisation of numerous weaknesses and drawbacks of react-tether that I believe don't allow the integration of Popover component according to latest best practices and standards in development of React components, as well as according to our Chapter agreements.
A complete comparison in size, usage and features differences between the two libraries (in depth below):
Maintainability & Currency of the Library
First thing that strikes clear from this comparison is that react-tether is not really being developed or maintained anymore, the latest release of core library dates back to over a year ago in March 2021 and the wrapper library even later, latest release having been over 2 years ago - 13 Jan 2020. Meanwhile, react-popper seems to keep consistent with releases with latest one 4 days ago.
Same goes for the current activity on their respective repositories, react-tether has only 2 issues and 0 pull requests, against 12 issues / 16 pull requests on react-popper repo. In addition to that, react-popper has an active contributors community on its repo's discussions, something that cannot be said about react-tether. It seems safe to say, that react-tether hasn't really been maintained since around the start of 2020.
Usage (Downloads / Users)
The fact that react-tether is being hardly used anymore is also visible through the user and download numbers. react-tether has around 40 000 weekly downloads against 6.3 MILLION weekly downloads of react-popper. 172 dependent projects on react-tether against 2 338 dependent projects on react-popper, as well as ~1200 developers using react-tether vs. ~ 341 000 devs using react-popper are pretty similar ratio of difference as downloads.
Size
There is a pretty significant difference in sizes of these deps too. react-tether with its core dependency included weights at 54.3kb while react-popper with its core dependency weights at 26kb, that is half of react-tether size.
React 18 Support
Probably the most important and relevant difference (also related to: [Issue #212]) is that react-popper devs have already migrated the lib to use and support React 18 features, in its latest release, which would enable us to already support React 18 features in components that use positioning lib (Popover, and consequently also Tooltip and Datepicker components). Looking at activity on react-tether, we cannot really expect it will support React 18 any time soon, if ever.
With React 18 comes also possibility to use latest features and methodologies, for example: concurrent rendering, rendering with React Portal, etc.
Functional Programming & Hooks
Because react-tether TetherComponent is declared as a class component, there is a couple more disadvantages that need to be considered about react-tether here:
However, there is quite a big difference in placement and offset setting with react-tether and react-popper...
With react-tether, we have to re-declare in code every single option of placement with helper function so that we can format the attachment value correctly, to be passed into TetherComponent (because we have multiple components defining different sets of placements), but also we have to manually redefine the offset based on the placement of the Popover content
react-popper on the other side, already provides type definitions for all placement options (so we don't have to redefine them in our source code) -> we only need to pass the desired placement and it deals with the positioning. In addition react-popper also automatically updates the selected offset value, so that it fits with current placement. (e.g. you change positioning from top to bottom -> offset changes from bottom margin to top margin)
Also about placement and staying in the viewport...
If you force placement that cannot possibly be positioned in the remaining space in the window (e.g. your trigger is on the left edge of the screen and you apply placement = left), react-tether will not adjust the position of the content, it will flow outside the viewport and will not be visible (which is, of course, bad UX).
react-popper detects that for you out of the box, and always repositions the Popover content somewhere else, where it can be fully visible in the viewport.
Loom presentation of this behaviour: https://www.loom.com/share/5b2bfc065c304284bf3a6988353b18d3
Which components would be affected by this change?
If interested in more in depth explanation of why the FloatingUI react-popper implementation is better with much modern API, as well as much better browser compatibility than original Popper or Tether libs, in regards to using JS for repositioning, clipping and overflowing issues, and more, check out this article: https://blog.logrocket.com/popper-vs-floating-ui/
The text was updated successfully, but these errors were encountered: