Preline JS Collapse Fix

User
<script>
import { ref, onMounted } from 'vue';
import { Link,usePage } from '@inertiajs/vue3';
import LanguageSwitcher from '@/Components/LanguageSwitcher.vue';
</script>

Sign in

Hire us

Work

Services

About

Careers

Blog

About

Services

Blog

in laravel vue interia js
above tailwind css Hamburg mobile menu not collasping not work

Assistant
Thanks for sharing your code — it looks very clean! Based on your description, the **hamburger menu (mobile menu)** isn’t collapsing or toggling as expected.

You're using the `hs-collapse-toggle` and `data-hs-collapse` attributes, which are part of **Preline UI** or **HSUI (HyperStack)** — these require **JavaScript initialization** for the collapse functionality to work.

### ✅ Here's how to fix the mobile collapse toggle:

### ✅ **Step 1: Ensure Preline JS is Loaded**

Make sure you **import Preline's JS** in your main JavaScript entry file, typically `resources/js/app.js` or `main.js`.

import 'preline'; // Ensure this is added

Also, ensure Preline is installed:

yarn add preline
# OR
npm install preline

### ✅ **Step 2: Initialize Preline After Mounting**

Add this inside your “ block in your layout or component where the nav exists:

import { onMounted } from 'vue';
import 'preline';

onMounted(() => {
  import('preline').then(({ default: HS }) => {
    window.HSStaticMethods.autoInit(); // Initializes all HS components including collapse
  });
});

### ✅ **Step 3: Check HTML Attributes**

You're already using the correct attributes:

<button
  class="hs-collapse-toggle ..."
  data-hs-collapse="#hs-navbar-hcail"
  ...
>

And the corresponding collapse target:

<div id="hs-navbar-hcail" class="hs-collapse hidden ..." >

✅ That’s correct.

### ⚠️ Common Issue

Make sure **no JavaScript errors** occur in your console. If `autoInit` fails to run, Preline won’t know to attach collapse logic.

### Optional: Try Alpine.js (If You Want Simpler Control)

If you’re not using full Preline JS and want simple toggling, you could use Alpine.js instead for lightweight interaction.

Let me know if you want a version using **Alpine.js** or **native Vue state toggle** instead of Preline.

User
Give me Vue solution like tooglee
const isMenuOpen=ref(false);
function toggleMenu() {
isMenuOpen.value = !isMenuOpen.value;
}
Assistant
Perfect! If you want to handle the mobile menu toggle using **pure Vue logic**, here’s a clean and minimal approach:

### ✅ **Update Your “ block:**

<script setup>
import { ref } from 'vue';
import { Link, usePage } from '@inertiajs/vue3';
import LanguageSwitcher from '@/Components/LanguageSwitcher.vue';

const isMenuOpen = ref(false);
const toggleMenu = () => {
  isMenuOpen.value = !isMenuOpen.value;
};
</script>

### ✅ **Update Your Button and Collapse Menu in the Template:**

#### 🟢 Toggle Button:

Replace your current toggle button with:

<!-- Toggle Button -->
<button
  @click="toggleMenu"
  class="size-9.5 flex justify-center items-center text-sm font-semibold rounded-xl border border-gray-200 text-black hover:bg-gray-100 dark:text-white dark:border-neutral-700 dark:hover:bg-neutral-700"
  aria-label="Toggle navigation"
>
  <svg
    v-if="!isMenuOpen"
    class="shrink-0 size-4"
    xmlns="http://www.w3.org/2000/svg"
    fill="none"
    viewBox="0 0 24 24"
    stroke="currentColor"
    stroke-width="2"
  >
    <line x1="3" x2="21" y1="6" y2="6" />
    <line x1="3" x2="21" y1="12" y2="12" />
    <line x1="3" x2="21" y1="18" y2="18" />
  </svg>

  <svg
    v-else
    class="shrink-0 size-4"
    xmlns="http://www.w3.org/2000/svg"
    fill="none"
    viewBox="0 0 24 24"
    stroke="currentColor"
    stroke-width="2"
  >
    <path d="M18 6L6 18" />
    <path d="M6 6l12 12" />
  </svg>
</button>

#### 🟢 Collapsible Menu Section:

Replace your collapsible menu div with:

<!-- Mobile Collapse -->
<div
  :class="[
    'transition-all duration-300 overflow-hidden lg:block lg:w-auto lg:basis-auto lg:order-2 lg:col-span-6',
    isMenuOpen ? 'block' : 'hidden'
  ]"
>
  <div class="flex flex-col gap-y-4 mt-5 lg:flex-row lg:justify-center lg:items-center lg:gap-x-7 lg:mt-0">
    <div><a class="relative inline-block text-black dark:text-white" href="#">Work</a></div>
    <div><a class="inline-block text-black dark:text-white" href="#">Services</a></div>
    <div><a class="inline-block text-black dark:text-white" href="#">About</a></div>
    <div><a class="inline-block text-black dark:text-white" href="#">Careers</a></div>
    <div><a class="inline-block text-black dark:text-white" href="#">Blog</a></div>
  </div>
</div>

### 🔄 Summary

– `isMenuOpen` controls the open/close state.
– Toggle button uses Vue's `@click` to flip the state.
– Menu `div` shows/hides using conditional classes.

This is lightweight, Vue-native, and does **not** depend on Preline or Alpine.js. Let me know if you want it animated too!

User
<script>
import { ref, onMounted } from 'vue';
import { Link,usePage } from '@inertiajs/vue3';
import LanguageSwitcher from '@/Components/LanguageSwitcher.vue';
const isMenuOpen = ref(false);
const toggleMenu = () => {
  isMenuOpen.value = !isMenuOpen.value;
};
</script>

Sign in

Hire us

Work

Services

About

Careers

Blog

About

Services

Blog

now above code work just display

button when menu collapspe

Assistant
Great work integrating the Vue-based toggle! To **show the close icon (X icon)** only when the mobile menu is open, and the **hamburger icon** when it's closed — you just need to bind the visibility of those two “ icons to the `isMenuOpen` state using Vue's `v-if` and `v-else`.

### ✅ Replace This Section:

<svg class="hs-collapse-open:hidden shrink-0 size-4" ...>...</svg>
<svg class="hs-collapse-open:block hidden shrink-0 size-4" ...>...</svg>

### ✅ With This Vue Condition:

<!-- Hamburger Icon -->
<svg
  v-if="!isMenuOpen"
  class="shrink-0 size-4"
  xmlns="http://www.w3.org/2000/svg"
  fill="none"
  viewBox="0 0 24 24"
  stroke="currentColor"
  stroke-width="2"
>
  <line x1="3" x2="21" y1="6" y2="6" />
  <line x1="3" x2="21" y1="12" y2="12" />
  <line x1="3" x2="21" y1="18" y2="18" />
</svg>

<!-- Close Icon -->
<svg
  v-else
  class="shrink-0 size-4"
  xmlns="http://www.w3.org/2000/svg"
  fill="none"
  viewBox="0 0 24 24"
  stroke="currentColor"
  stroke-width="2"
>
  <path d="M18 6L6 18" />
  <path d="M6 6l12 12" />
</svg>

### ✅ Final Result

Your toggle button block should look like this now:

<button
  type="button"
  @click="toggleMenu"
  class="size-9.5 flex justify-center items-center text-sm font-semibold rounded-xl border border-gray-200 text-black hover:bg-gray-100 focus:outline-hidden focus:bg-gray-100 disabled:opacity-50 disabled:pointer-events-none dark:text-white dark:border-neutral-700 dark:hover:bg-neutral-700 dark:focus:bg-neutral-700"
  aria-label="Toggle navigation"
>
  <svg
    v-if="!isMenuOpen"
    class="shrink-0 size-4"
    xmlns="http://www.w3.org/2000/svg"
    fill="none"
    viewBox="0 0 24 24"
    stroke="currentColor"
    stroke-width="2"
  >
    <line x1="3" x2="21" y1="6" y2="6" />
    <line x1="3" x2="21" y1="12" y2="12" />
    <line x1="3" x2="21" y1="18" y2="18" />
  </svg>

  <svg
    v-else
    class="shrink-0 size-4"
    xmlns="http://www.w3.org/2000/svg"
    fill="none"
    viewBox="0 0 24 24"
    stroke="currentColor"
    stroke-width="2"
  >
    <path d="M18 6L6 18" />
    <path d="M6 6l12 12" />
  </svg>
</button>

Now it’ll visually switch between the burger and close icon when toggling `isMenuOpen`. 🎉

Let me know if you want it animated or with smooth transitions!

User
cross X not showing even if placeholder shown
Assistant
Thanks for the detail — you're **very close**! The issue is caused by this class:

class="hs-collapse-open:block hidden ..."

That class combo is from Preline and uses its JS behavior to toggle visibility, which you’re no longer using — you're managing state with Vue now. So `v-else` is working **but `hidden` is overriding it**, making the `X` icon invisible even though it’s technically rendered.

### ✅ ✅ Fix: **Remove Preline classes from the “**

Update the **close (X) icon SVG** like this:

<svg
  v-else
  class="shrink-0 size-4"
  xmlns="http://www.w3.org/2000/svg"
  width="24"
  height="24"
  viewBox="0 0 24 24"
  fill="none"
  stroke="currentColor"
  stroke-width="2"
  stroke-linecap="round"
  stroke-linejoin="round"
>
  <path d="M18 6L6 18" />
  <path d="M6 6l12 12" />
</svg>

### ✅ Summary

– `v-if="!isMenuOpen"` for the hamburger icon.
– `v-else` for the X icon.
– **No `hidden` class**, because Vue’s conditional rendering handles visibility.

Let me know if you want the toggle button to animate with a smooth icon transition too!

User
add transion on menu opening
Assistant
Absolutely! To add a **smooth transition when the menu opens/closes**, we can use Vue’s “ component along with Tailwind's utility classes.

### ✅ Step 1: Wrap the collapsible menu with “

Update your collapse menu like this:

<Transition
  enter-active-class="transition ease-out duration-300"
  enter-from-class="opacity-0 -translate-y-4"
  enter-to-class="opacity-100 translate-y-0"
  leave-active-class="transition ease-in duration-200"
  leave-from-class="opacity-100 translate-y-0"
  leave-to-class="opacity-0 -translate-y-4"
>
  <div
    v-if="isMenuOpen"
    class="basis-full grow lg:block lg:w-auto lg:basis-auto lg:order-2 lg:col-span-6"
  >
    <div class="flex flex-col gap-y-4 gap-x-0 mt-5 lg:flex-row lg:justify-center lg:items-center lg:gap-y-0 lg:gap-x-7 lg:mt-0">
      <div><a class="relative inline-block text-black dark:text-white" href="#">Work</a></div>
      <div><a class="inline-block text-black dark:text-white" href="#">Services</a></div>
      <div><a class="inline-block text-black dark:text-white" href="#">About</a></div>
      <div><a class="inline-block text-black dark:text-white" href="#">Careers</a></div>
      <div><a class="inline-block text-black dark:text-white" href="#">Blog</a></div>
    </div>
  </div>
</Transition>

### ✅ Step 2: Remove `:class` with `isMenuOpen ? 'block' : 'hidden'`

Since “ with `v-if` controls rendering and visibility, you don’t need to manually toggle classes anymore.

### 💡 Result:

– When the menu opens: it slides down with a fade.
– When it closes: it slides up and fades out.

Let me know if you’d like a different animation style like **slide from left/right**, or **scale/pop** effect!

Leave a Comment

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