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 component
  • content: The DOM element of the content component
  • destination: The DOM element where the content component is going to be inserted
  • previousHorizontalPosition: The string with the horizontal position the component had in the last time it was repositioned. If you don't provide any or you pass horizontalPosition="auto" it will be "left" or "right" depending on the space around the trigger
  • horizontalPosition: The string with the current horizontal position. If you don't provide any or you pass horizontalPosition="auto" it will be "left" or "right" depending on the space around the trigger
  • previousVerticalPosition: The string with the vertical position the component had in the last time it was repositioned. If you don't provide any or you pass verticalPosition="auto" it will be "above" or "below" depending on the space around the trigger
  • verticalPosition: The string with the current vertical position. If you don't provide any or you pass verticalPosition="auto" it will be "above" or "below" depending on the space around the trigger
  • matchTriggerWidth: Boolean that express the intention of the developer to make the dropdown have the same width as the trigger
  • renderInPlace: 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 horizontalPosition
  • verticalPosition: The new value of verticalPosition
  • style: An object containing the CSS properties that will position the object. It supports top, left, right and width

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.

Click me

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.

Click me

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.