chakra-ui / ark

A headless library for building reusable, scalable design systems that works for a wide range of JS frameworks.

Home Page:https://ark-ui.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Nuxt3] Combobox.Positioner incorrect position of content

bogdan0083 opened this issue · comments

Description

Hey guys! Thank you for creating such a beautiful library ❤️

I created nuxt3 project and installed @ark-ui/vue library. Tried to use Combobox. It works, but position of content is calculated incorrectly. I expect it to be UNDER input field. Instead, it shows at the top left corner:

Снимок экрана 2024-02-16 в 19 54 48

Link to Reproduction (or Detailed Explanation)

https://stackblitz.com/edit/nuxt-starter-fzamjd?file=components%2FComboboxArk.vue

Steps to Reproduce

  1. Create empty Nuxt 3 project (in my case it's 3.10.1 version)
  2. Install @ark-ui/vue
  3. Create Combobox component (I use UnoCSS for styling, but no styles added for Combobox.Positioner or Combobox.Content:
<script setup>
import { ref } from 'vue';
import { Combobox } from '@ark-ui/vue';

const advancedItems = ref([
  { label: 'React', value: 'react' },
  { label: 'Solid', value: 'solid' },
  { label: 'Vue', value: 'vue' },
  { label: 'Svelte', value: 'svelte', disabled: true },
]);

const inputValue = ref('');

const onInputValueChange = (details) => {
  console.log(details);
  inputValue.value = details.value;
};

const onValueChange = (details) => {
  console.log(details);
  inputValue.value = '';
};
</script>

<template>
  <Combobox.Root
    :items="advancedItems"
    multiple
    v-slot="api"
    :onInputValueChange="onInputValueChange"
    :onValueChange="onValueChange"
  >
    <Combobox.Label>Framework</Combobox.Label>
    <Combobox.Control
      class="flex items-center flex-wrap relative pr-12 gap-x-3"
    >
      <div
        v-for="selectedItem in api.value"
        :key="selectedItem"
        class="inline-flex grow-0 shrink-0"
      >
        {{ selectedItem }}
      </div>
      <div class="min-w-10 w-[fit-content] inline-flex grow shrink">
        <Combobox.Input
          :value="inputValue"
          class="text-gray-500 bg-transparent b-none w-full block"
        />
      </div>
      <Combobox.Trigger class="absolute w-12 top-0 right-0"
        >Open</Combobox.Trigger
      >
    </Combobox.Control>
    <Teleport to="body">
      <Combobox.Positioner>
        <Combobox.Content>
          <Combobox.ItemGroup id="framework">
            <Combobox.ItemGroupLabel htmlFor="framework"
              >Frameworks</Combobox.ItemGroupLabel
            >
            <Combobox.Item
              v-for="item in advancedItems"
              :key="item.value"
              :item="item"
            >
              <Combobox.ItemText>{{ item.label }}</Combobox.ItemText>
              <Combobox.ItemIndicator>✓</Combobox.ItemIndicator>
            </Combobox.Item>
          </Combobox.ItemGroup>
        </Combobox.Content>
      </Combobox.Positioner>
    </Teleport>
  </Combobox.Root>
</template>
  1. Use your newly created component inside app.vue:
<template>
  <div class="flex flex-col w-300px">
    <h2>Combobox Ark example</h2>
    <Combobox />
  </div>
</template>

<script setup>

useHead({
  bodyAttrs: {
    class: 'text-gray-100 bg-gray-960 l:(text-gray-900 bg-white-100)',
  },
});
</script>
  1. run npm run dev and see the result. Content has wrong position on open (it's in the top left corner. I expect it to be under input)

Ark UI Version

@ark-ui/vue: 0.11.0

Framework

  • React
  • Solid
  • Vue

Browser

Firefox

Additional Information

No response

Here's the same example with Vue 3 and Vite, without SSR. You can see that the position of content is correct.

Thank you for opening this issue. I think it's similar to the problem with Portal in React with SSR

@bogdan0083 I've also stumble upon this issue some weeks ago, it seems even though Nuxt has SSR support for Teleport sometimes it adds the div above <div id="__nuxt"> during hydration. I had to wrap the teleport inside of <ClientOnly> as they describe in the docs.

There is, though, an implement coming up that maybe will fix this 🤔
nuxt/nuxt#25041
nuxt/nuxt#25043

@bogdan0083 I've also stumble upon this issue some weeks ago, it seems even though Nuxt has SSR support for Teleport sometimes it adds the div above <div id="__nuxt"> during hydration. I had to wrap the teleport inside of as they describe in the docs.

There is, though, an implement coming up that maybe will fix this 🤔 nuxt/nuxt#25041 nuxt/nuxt#25043

Hmm, I've just tried your solution with <ClientOnly> wrapper of Teleport and it still doesn't work 🤔 . Tried it on my bug reproduction example (It doesn't have ClientOnly wrapper now).

But I guess nuxt is definitely to blame here, that's for sure.

But I guess nuxt is definitely to blame here, that's for sure.

Mostly Vue SSR behavior - we'd love to mimic the client-side Vue behavior but it'd lead to hydration errors. Nevertheless, with the linked PR it should work fine and follow the best practices 👍