SvelteKit returns window.innerWidth as undefined on initial page load

Viewed 108

I have two separate components, one that is intended for mobile devices and the other for desktop. Only one component should displayed at a time, depending on width of the user's browser window. Here's a condensed version that I have:

<script>
    let innerWidth
</script>

<svelte:window bind:innerWidth />

<p>
  Inner Width: {innerWidth}
</p>

{#if innerWidth > 800}
    Desktop Content
{:else}
    Mobile Content
{/if}

I noticed that when I load the page, {innerWidth} quickly switches from undefined to the appropriate value. For desktop users, this is a problem because the Mobile content is displayed because at the time of evaluating {#if innerWidth > 800}, Svelte has innerWidth = undefined.

Interestingly enough, this problem only occurs when I load the page directly. If I had this feature on /subpage, the intended functionality would work if I visited /index and then /subpage.

Is there a way to return the appropriate value on initial page load without it recognizing undefined? I would like to avoid using CSS media queries, but it is a last resort.

3 Answers

Is there a way to return the appropriate value on initial page load without it recognizing undefined?

Not with the default configuration as SvelteKit uses server-side rendering on the first page load. There is no way to get that information on the server.

If you want to prevent displaying the wrong content you can also wrap your content in an additional #if.

{#if innerWidth != null}
    {#if innerWidth > 800}
        Desktop Content
    {:else}
        Mobile Content
    {/if}
{/if}

I think it is a DOM event ordering issue. innerWidth might not be yet available when you try to access it for the first time. Browsers don't have it, until they have done full CSS layouting.

If you navigate /index first and then /subpage there is already one value loaded in innerWidth because the front page has been displayed, though this value could be wrong during the navigation until the relayout occurs.

It is unlikely that you can have a proper value at the page load time, because that's how web browsers work.

You are getting the error because you are trying to access the window element in your server (your server is not a browser) you need a way to what for the server to finish pressing the request so that when it gets to the client, you can retrieve the data you want, in this can use the svelte browser object to check if you are on the server or client.

<script>
    import { browser } from '$app/env';

    let innerWidth // you can also set your default width

    if (browser){
        innerWidth = window.innerWidth;
    }
</script>


{#if innerWidth > 800}
   <DesktopContent />
{:else}
   <MobileContent />
{/if}

if you want to scale on resize, you can use this instead

<script>
    import { browser } from '$app/env';

    let innerWidth // you can also set your default width

    const updateWindowSize = () =>{
        innerWidth = window.innerWidth;
    }
    if (browser){
        updateWindowSize() // to set the initial window size
        window.onresize = updateWindowSize; // run when ever the window size change
        
    }
</script>
Related