'Access a DOM element in javascript after it is shown - Svelte

I'm creating a custom select dropdown component, simplified below:

<script lang="ts">
    let optionsOpen: boolean = false;

    function onSelectClick(e) {
        optionsOpen = !optionsOpen;
        let p = e.target.closest('.select');
        let child = p.querySelector('.options');
        console.log(child);  //always null
    }
</script>


<div class="select" on:click={onSelectClick}>
    {#if optionsOpen}
        <div class="options">
            My Options
        </div>
    {/if}
</div>

From the above you'll see that when the div with .select class is clicked, the option container opens (via the optionsOpen variable).

However, in the onSelectClick I need to access the options div DOM element once it has been opened. I can access the select div, but not the child options div, it always returns null.

I suspect it may be because the options element it not yet available when I try to access it, even though I am setting the optionsOpen variable to prior to my attempt to access.

Any ideas how to access the options div after it is made visible?



Solution 1:[1]

Another way to approach this would be to use a Svelte action. This is a custom function that runs when a DOM node is added and gives you access to the node directly.

This is more idiomatic than using querySelector.

<script>
    let optionsOpen = false;

    function onSelectClick(e) {
        optionsOpen = !optionsOpen;
    }
    
    function adjustPosition(node) {
        // this will run when <div class="options"> is added to the DOM
        node.style.top = '300px'; // or whatever you want to do
    }
</script>


<div class="select" on:click={onSelectClick}>
    Select
    {#if optionsOpen}
        <div class="options" use:adjustPosition>
            My Options
        </div>
    {/if}
</div>

Solution 2:[2]

I was able to resolve this by using the tick function, the modified function is below:

<script lang="ts">
    let optionsOpen: boolean = false;

    async function onSelectClick(e) {
        optionsOpen = !optionsOpen;
        await tick();
        let p = e.target.closest('.select');
        let child = p.querySelector('.options');
        console.log(child);  //not null anymore
    }
</script>

I would be interested in other possible solutions in addition to the above if available and be informed if the above solution is not the correct way to handle such a situation.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Geoff Rich
Solution 2 Musaffar Patel