| .. | ||
| lib | ||
| src | ||
| LICENSE | ||
| package.json | ||
| README.md | ||
Ultra Tiny, Opinionated Positioning Engine
NanoPop is an ultra-tiny positioning engine. But wait isn't there PopperJS? Yeah - and PopperJS is great! But there are tons of features you might not need in most cases. This library is brotlied only ~ 700 Bytes (PopperJS is around 3kB).
What are the use-cases compared to PopperJS?
- Situations where you want full controll over positioning, including handling events such as scrolling / resize manually.
- Performance-critical cases with lots of elements [...] nanopop will only makes changes if you say so.
- Poppers with minimal footprint such as drop-downs and tooltips which don't require much configurability.
- You might have some special needs about how your popper behaves. NanoPop could be used as super-class and you can, based on what's required, extend NanoPop as you will :)
This library was originally part of pickr - now ported to TS with tests and a few updates / bug-fixes.
Getting Started
Install via npm:
$ npm install nanopop
Install via yarn:
$ yarn add nanopop
Include directly via jsdelivr:
<script src="https://cdn.jsdelivr.net/npm/nanopop/lib/nanopop.min.js"></script>
Using JavaScript Modules:
import {NanoPop} from 'https://cdn.jsdelivr.net/npm/nanopop/lib/nanopop.min.mjs'
Usage
const reference = document.querySelector('.btn');
const popper = document.querySelector('.dropdown');
const nanopop = new NanoPop(reference, popper);
// Updating the popper-position
nanopop.update();
The popper-element must have set
positiontofixed.
All options
const nanopop = new NanoPop(reference, popper, {
// The DOMRect of the container, this is the default:
container: document.documentElement.getBoundingClientRect(),
// Margin between the popper element and the reference
margin: 8,
// Preferred position, any combination of [top|right|bottom|left]-[start|middle|end] is valid.
position: 'bottom-start',
// Sometimes there's no way to position the popper element without clipping it.
// Turn this on if, in case there's no non-clipping position, want to apply the wanted position forcefully.
// The .update() function will return false in any case it fails so you can handle this separately.
// Attention: If this is set to false and you do not take care about handling the clipped element yourself it'll be positioned on the top-left corner of the container-element (most of the time this is the document element itself).
forceApplyOnFailure: false,
// In case the variant-part (start, middle or end) cannot be applied you can specify what (and if)
// should be tried next.
variantFlipOrder: {
start: 'sme', // In case of -start try 'start' first, if that fails 'middle' and 'end' if both doesn't work.
middle: 'mse',
end: 'ems'
},
// The same as variantFlipOrder, but if all variants fail you might want to try other positions.
positionFlipOrder: {
top: 'tbrl', // Try 'top' first, 'bottom' second, 'right' third and 'left' as latest position.
right: 'rltb',
bottom: 'btrl',
left: 'lrbt'
}
});
Functions
nanopop.update(newOptions?: Partial<Options>)- Update the position and optionally update the options of this NanoPop instance. It'll return a position-pair (For exampletefor Top-End) ornullbased on if it was possible to find a position for the popper without clipping it.
Tip: The returned position-pair is perfect for tool-tips to give them a little arrow!
Properties
nanopop.version- Current version.
These are static default-values used in case you're not specifying something else:
NanoPop.defaultVariantFlipOrder- DefaultvariantFlipOrdervalues.NanoPop.defaultPositionFlipOrder- DefaultpositionFlipOrder.
Caveats
- The popper-element must have
positionset tofixed. windowis (currently) the only bounding-element supported.- The library does not perform any automatic updates if the window gets resized, or the user scrolls, you have to take care of that
yourself and call
update()in the case. - You might have to fiddle around with
z-indexto make it work inside of complex, nested, scrollable containers.