Custom position
In a previous section we already say that the dropdown bundles a few positioning strategies both horizontally and vertically.
But you don't want to be limited to the positioning strategies I designed for you. You might want the dropdown to float to the left of the trigger or perhaps one inch south-west of it.
Fear not, my friend, the component has an escape valve for this. You can design your own positioning function and pass it to the component. It just has to fulfill a specific contract.
calculatePosition
This function is the only thing you have to implement to tell the component where it should be positioned.
The complete signature of the function is:
calculatePosition(trigger, content, destination, {
previousHorizontalPosition, horizontalPosition, previousVerticalPosition,
verticalPosition, matchTriggerWidth })
trigger
: The DOM element of the trigger componentcontent
: The DOM element of the content componentdestination
: The DOM element where the content component is going to be insertedpreviousHorizontalPosition
: The string with the horizontal position the component had in the last time it was repositioned. If you don't provide any or you passhorizontalPosition="auto"
it will be"left"
or"right"
depending on the space around the triggerhorizontalPosition
: The string with the current horizontal position. If you don't provide any or you passhorizontalPosition="auto"
it will be"left"
or"right"
depending on the space around the triggerpreviousVerticalPosition
: The string with the vertical position the component had in the last time it was repositioned. If you don't provide any or you passverticalPosition="auto"
it will be"above"
or"below"
depending on the space around the triggerverticalPosition
: The string with the current vertical position. If you don't provide any or you passverticalPosition="auto"
it will be"above"
or"below"
depending on the space around the triggermatchTriggerWidth
: Boolean that express the intention of the developer to make the dropdown have the same width as the triggerrenderInPlace
: Boolean that express if the content will be rendered in place. Useful since very usually the reposition logic must be entirely different
The return value of this function must also be an object with a specific
shape:
{ horizontalPosition, verticalPosition, style }
horizontalPosition
: The new value of horizontalPositionverticalPosition
: The new value of verticalPositionstyle
: An object containing the CSS properties that will position the object. It supportstop
,left
,right
andwidth
Sounds like a lot, but with an example you will see that it's not really hard. Let's create a dropdown that opens to the right of the trigger, vertically centered with it.
You can resize the window and scroll and you can see that the content stays
just where it should. It will even reposition automatically if the content
inside changes thanks to the magic of
MutationObservers
.
The key concept that you need to extract is that all the machinery to position the content and reposition when the content, scroll or screen changes is handled by the dropdown, so the only missing piece you have to provide is the function that calculates the cordinates.