Reusable Input Datalist
Tags: webdev, devjournal, html, javascript
Published: 2024-04-06 16:30:00

![Reusable Input Datalist](https://i.imgur.com/LY6ar4M.gif)

Hello Punk! In my daily boring...

I found something interesting that I will share with you, this is not too fancy or glam but still "fun-cy" for me, cz In my stupid knowledge this is really helpful and enough for me and myself.

## HTML5 Input Datalist

At least, this is what [W3Schools](https://www.w3schools.com/tags/tag_datalist.asp) said in their example:

![W3Schools Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/su65zksgukina4cm8xlj.png)

### What if I wrap inside PHP Function?

When I work with [HTMX](https://htmx.org) I need isolated component that can be reusable a form. So I create a PHP Function that generate the Input Datalist.

```php
// Filename: helpers/Utils.php

public static function selectSearch(string $inputId, array $options, int|string $selected = ''): string
{
    $inputHTML = '<div class="relative">';
    $inputHTML .= '<input type="text" id="' . $inputId . '" list="" placeholder="Search..." autocomplete="off" class="transition-[0.2s] w-full input input-sm input-bordered focus:shadow-md" />';
    $inputHTML .= '<datalist id="' . $inputId . '_list" class="box-border overflow-y-auto absolute top-full mt-1 max-h-40 bg-white border shadow-md">';

    $selectedText = '';
    $selectedValue = '';
    foreach ($options as $option) {
        $text = \explode('#', $option)[1];
        $value = \explode('#', $option)[0];
        if ($selected == $value) {
            $selectedText = $text;
            $selectedValue = $value;
        }
        $inputHTML .= '<option class="block p-1 mb-px cursor-pointer hover:bg-gray-200" value="' . $option . '">' . $text . '</option>';
    }

    $inputHTML .= '</datalist>';
    $inputHTML .= '<input type="hidden" name="' . $inputId . '" id="target_' . $inputId . '" value="'.$selectedValue.'" />';
    $inputHTML .= '</div>';
    $inputHTML .= '<script type="text/javascript">';
    $inputHTML .= 'fancyDropdown("' . $inputId . '");';
    $inputHTML .= 'setTimeout(() => document.getElementById("' . $inputId . '").value = "'.$selectedText.'", 350);';
    $inputHTML .= '</script>';

    return $inputHTML;
}

```

I create a static function inside `Utils` class so I can use that function everywhere in my project.

_Is that using TailwindCSS?_ Yes, it's too dirty. But fck it! It's work! (Don't blame on me, if you really programmer so read it)

You can see this `script`:

```php
$inputHTML .= '<script type="text/javascript">';
$inputHTML .= 'fancyDropdown("' . $inputId . '");';
$inputHTML .= 'setTimeout(() => document.getElementById("' . $inputId . '").value = "' . $selectedText . '", 350);';
$inputHTML .= '</script>';
```

Yes! Again I wrote JavaScript as a string in PHP, why not! And where is the fckin `fancyDropdown` come from?!

Here is, I found a Question in StackOverflow that asked about

![Question in StackOverflow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o8s8zzm616r5qtdiug3b.png)
> The Question: [https://stackoverflow.com/q/13693482](https://stackoverflow.com/q/13693482)

Yes! Around 11 years ago, and the solution that match with my need is come around

![the solution that match with my need](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ldh0h56rmmt8han5md6.png)
> The Solution: [https://stackoverflow.com/a/76178626](https://stackoverflow.com/a/76178626)

The updated version of

![The updated version](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1rt1fh4vfbqudmx1l21y.png)
> Original Answer: [https://stackoverflow.com/a/74786719](https://stackoverflow.com/a/74786719)

Here is this code:

```javascript
function fancyDropdown(inputId) {
    const input = document.getElementById(inputId);
    const target = document.getElementById('target_' + inputId);
    const datalist = input.nextElementSibling;
    let minWidth = datalist.offsetWidth;

    function outputsize() {
        if (input.offsetWidth < minWidth) {
            datalist.style.minWidth = input.offsetWidth + 'px';
        } else {
            datalist.style.width = input.offsetWidth + 'px';
        }
    }

    new ResizeObserver(outputsize).observe(input);

    input.addEventListener("input", function(e) {
        datalist.style.display = "block";
        const text = input.value.toUpperCase();
        let hide = 1;
        for (let option of datalist.options) {
            if (option.value.toUpperCase().indexOf(text) > -1) {
                option.style.display = "block";
                hide = 0;
            } else {
                option.style.display = "none";
            }
        }
        if (hide) {
            datalist.style.display = "none";
        }
    });

    input.addEventListener("click", function(e) {
        let hide = 1;
        for (let option of datalist.options) {
            if (window.getComputedStyle(option, null).display == "block") hide = 0;
        }

        if (datalist.style.display == "block" || hide == 1) {
            datalist.style.display = "none";
        } else {
            datalist.style.display = "block";
        }
    });

    document.addEventListener("click", function(e) {
        if (e.target.tagName == "OPTION") {
            let inputValue = e.target.value.split('#');
            input.value = inputValue[1];
            target.value = inputValue[0];
        }
        if (e.target.tagName !== "DATALIST" && e.target.tagName !== "INPUT") {
            datalist.style.display = "none";
        }
    });

    datalist.style.display = "none";
}
```