gtag('config', 'G-0PFHD683JR');
Price Prediction

The appropriate offer for dedicated drop -down elements: Guidance guide

Do you know this feeling when creating your own component instead of improving the hypothetical HTML components? Your design team created something beautiful, but browsers will not support it outside the box, and its repair everywhere becomes a nightmare. We all know this pain, but these challenges make our function interesting.

Today, I wanted to talk about one dilemma waiting for us during this exciting journey: putting the drop -down elements, such as the selected lists or the date of history.

Fully

Initially, it seems position: absolute It solves all our problems, and it does some extent. But then, conditional windows destroy everything.

If the drop is overflowing, it is cut. Certainly, you can scroll down and see it, but it is better to pray that your designer cannot reach you with a sharp object.

This is far from perfection – we can do better.

Fix it with 'fixed'

If we want to display the content on everything, we need position: fixed. The only problem is that we will lose the coordinates of the original element: the fixed elements are completely independent by nature. This means that the only thing we have to do is to determine the accurate coordinates of the drop -down element in these cases:

  • When we show it.
  • When its content is changed.
  • When we make the window and/or the passive parent.
  • When we change the size of the window and/or the scrolling parent.

We also need to determine if it will be shown above the switch if it is very close to the bottom of the screen. He feels implemented.

I will use Vue.js, but it should be easy to follow even if you prefer to respond or angular.

Let’s approach this joint

Here is the structure that we will use:

export const useDropdownAttributes = () => {
  const dropdownWidth = ref('');
  const dropdownTop = ref('');
  const dropdownBottom = ref('');
  const dropdownLeft = ref('');
  const isDirectedUpwards = ref(false);
  const togglerRect = ref();
  const dropdownRect = ref();

  const autodetectPosition = (
    isDropdownDisplayed: Ref,
    togglerElement: HTMLElement | null = null,
    dropdownElement: HTMLDivElement | null = null,
    dropdownContent: Ref | ComputedRef = ref([]),
    isUpwardPreferred = false,
  ) => {
    // ...
  }

  return {
    autodetectPosition,
    dropdownTop,
    dropdownBottom,
    dropdownLeft,
    dropdownWidth,
    isDirectedUpwards,
    togglerRect,
    dropdownRect,
  };
};

There are four variables to put the drop -down menu in addition to isDirectedUpwards Knowledge and the function that you update all. We also return two variables for Toggler and Retpown: This may be appropriate, for example, for tool hints that need to be aligned to the middle of the content.

As you may remember, we also need to deal with scrolling and change the scroll parent size, so let’s create a job to find:

const getFirstScrollableParent = (element: HTMLElement | null): HTMLElement => {
    const parentElement = element?.parentElement;
    if (!parentElement) return document.body;

    const overflowY = window.getComputedStyle(parentElement).overflowY;

    if (overflowY === 'scroll' || overflowY === 'auto') return parentElement;

    return getFirstScrollableParent(parentElement);
  };

Now, let’s add the main job:

  const autodetectPosition = (
    isDropdownDisplayed: Ref,
    togglerElement: HTMLElement | null = null,
    dropdownElement: HTMLElement | null = null,
    dropdownContent: Ref | ComputedRef = ref([]),
    isUpwardPreferred = false,
  ) => {
    if (!togglerElement || !dropdownElement) return;

    const updateDropdownAttributes = () => {
      togglerRect.value = togglerElement.getBoundingClientRect();
      dropdownRect.value = dropdownElement.getBoundingClientRect();
      dropdownWidth.value = `${togglerRect.value.width}px`;
      dropdownBottom.value = `${window.innerHeight - togglerRect.value.top}px`;
      dropdownTop.value = `${
        window.innerHeight - togglerRect.value.bottom - dropdownRect.value.height
      }px`;
      dropdownLeft.value = `${togglerRect.value.left}px`;
    };

    const handleResize = () => {
      requestAnimationFrame(updateDropdownAttributes);
    };

    const handleScroll = () => {
      requestAnimationFrame(updateDropdownAttributes);
    };

    watch(
      [isDropdownDisplayed, dropdownContent],
      ([newVal, _]) => {
        const scrollableParent = getFirstScrollableParent(togglerElement);
        if (!newVal) {
          window.removeEventListener('resize', handleResize);
          window.removeEventListener('scroll', handleScroll);
          scrollableParent.removeEventListener('resize', handleResize);
          scrollableParent.removeEventListener('scroll', handleScroll);
          return;
        }

        requestAnimationFrame(() => {
          const distanceFromBottom =
            window.innerHeight - togglerElement.getBoundingClientRect().bottom;
          const distanceFromTop = togglerElement.getBoundingClientRect().top;
          const dropdownHeight = dropdownElement.offsetHeight;

          isDirectedUpwards.value = isUpwardPreferred
            ? distanceFromTop > dropdownHeight
            : distanceFromBottom < dropdownHeight &&
              distanceFromTop > dropdownHeight;

          updateDropdownAttributes();
          window.addEventListener('resize', handleResize);
          window.addEventListener('scroll', handleScroll);
          scrollableParent.addEventListener('resize', handleResize);
          scrollableParent.addEventListener('scroll', handleScroll);
        });
      },
      { deep: true },
    );
  };

tiger isDropdownDisplayed and dropdownContent So we can respond to their updates.

Also tiger togglerElement and dropdownElementWhat we need to calculate the situation.

Finally, there isUpwardPreferred In the event that you want the drop -down menu above the alteration by default.

It’s time to relax and enjoy

In your ingredient, you will need something like this (assume that you added Refs to your and breastfeed exchange in the template):

const {
  autodetectPosition,
  dropdownTop,
  dropdownBottom,
  dropdownLeft,
  dropdownWidth,
  isDirectedUpwards,
} = useDropdownAttributes();

const togglerRef = ref();
const dropdownRef = ref();

const isDropdownShown = ref(false);

onMounted(() => {
  autodetectPosition(isDropdownShown, togglerRef.value?.$el, dropdownRef.value?.$el);
});

CSS will look like this:


.dropdown {
  position: fixed;
  bottom: v-bind('isDirectedUpwards ? dropdownBottom : dropdownTop');
  left: v-bind('dropdownLeft');

  width: v-bind('dropdownWidth');
  min-width: 0;
}

Vola. The drop -down menu is properly displayed even when it overflows and moves above the switch if there is not enough space below.

Since we are at the end of the article, I would like to leave you with something cheerful – but I am outside the ideas. So, I am afraid that “good luck” is all I have this time. good luck. 👋

You can find the full code on GitHub.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button