Search code examples
javascriptvue.jssafaritailwind-css

Vue 3 click event is not working on safari


I have this table component and I'm facing an issue with the @click event not firing on safari while being working just fine on chrome

  <table class="h-full w-full">
    <thead class="sticky top-0 rounded bg-gray-100 shadow-sm">
      <tr class="t-head">
        <th
          v-for="column in visibleCols"
          :key="column.index"
          class="min-w-fit whitespace-nowrap rounded border-r p-3 text-left font-medium text-gray-800 last:border-0"
          @mouseenter="showSortIcon({ column })"
          @mouseleave="hideSortIcon({ column })"
        >
          <div class="flex item-center gap-3">
            <div>{{ column.displayName || "" }}</div>
            <button
              v-if="isSortEnabled && (column as Column).isSortable"
              class="hover:text-indigo-600 transition-opacity duration-300 ease-in-out"
              :class="[
                activeSortColumn.column == column || (sortIconState.column == column && sortIconState.visible)
                  ? 'opacity-100'
                  : 'opacity-0',
              ]"
              @click="onSortIconClicked(column)"
            >
              <i
                class="fa-solid fa-arrow-up transition-all duration-300 ease-in-out"
                :class="[column == activeSortColumn.column && activeSortColumn.isDesc ? 'rotate-180' : 'rotate-0']"
              />
            </button>
          </div>
        </th>
      </tr>
    </thead>
    <tbody v-if="loading" class="bg-white">
      <tr>
        <td :colspan="visibleCols.length">
          <div class="flex">
            <i class="fa-solid fa-circle-notch m-auto animate-spin text-3xl text-indigo-600"></i>
          </div>
        </td>
      </tr>
    </tbody>
    <tbody v-else-if="data && data.length !== 0 && visibleCols.length !== 0" class="bg-white">
      <tr
        v-for="(row, index) in data"
        :key="index"
        class="border-b last:border-0"
        :class="{ 'cursor-pointer hover:bg-gray-100': areRowsClickable }"
        @click="handleRowClick(row)"
      >
        <td
          v-for="cell in visibleCols"
          :key="cell.index"
          class="min-w-fit whitespace-nowrap border-r px-3 py-2 text-left last:border-0"
          :class="cell.class"
        >
          <component :is="cell.component(row, emit)" v-if="!('accessor' in cell) && cell.component !== undefined" />
          <span v-else-if="'accessor' in cell && cell.component === undefined && row[cell.accessor] !== null">
            {{ row[cell.accessor] }}
          </span>
          <component
            :is="cell.component(row[cell.accessor])"
            v-else-if="'accessor' in cell && cell.component !== undefined"
          />
          <span v-else>---</span>
        </td>
      </tr>
    </tbody>
    <tbody v-else class="bg-white">
      <tr>
        <td :colspan="visibleCols.length">
          <slot name="empty-state">
            <div class="flex h-[200px]">
              <span class="m-auto">No data to display</span>
            </div>
          </slot>
        </td>
      </tr>
    </tbody>
  </table>

Also the tailwind hover effect is not showing as well. I inspected the page and found out the following:

  1. When I tried selected the table body with the element selection tool I was not able to.
  2. When I selected a row from the elements tab and this checked the hover checkbox the hover effect was rendered successfully. I'm using macOS Ventura 13.0 with safari version 16.1

Solution

  • My solution was the following: I changed the whole table structure to use divs instead. I utilized the following Tailwind classes:

    1. table
    2. table-row
    3. table-row-group
    4. table-cell

    The final result looked something like this

    <div class="table w-full table-auto" :class="gridCols">
          <!-- HEADER -->
          <div class="sticky top-0 table-row bg-gray-200">
            <div
              v-for="column in visibleCols"
              :key="column.index"
              class="table-cell whitespace-nowrap border-b border-r border-gray-300 p-3 text-left font-medium text-gray-800 last:border-r-0"
              @mouseenter="showSortIcon({ column })"
              @mouseleave="hideSortIcon({ column })"
            >
              <div class="item-center flex gap-3">
                <div>{{ column.displayName || "" }}</div>
                <button
                  v-if="isSortEnabled && (column as Column).isSortable"
                  class="transition-opacity duration-300 ease-in-out hover:text-indigo-600"
                  :class="[
                    activeSortColumn.column == column || (sortIconState.column == column && sortIconState.visible)
                      ? 'opacity-100'
                      : 'opacity-0',
                  ]"
                  @click="onSortIconClicked(column)"
                >
                  <i
                    class="fa-solid fa-arrow-up transition-all duration-300 ease-in-out"
                    :class="[column == activeSortColumn.column && activeSortColumn.isDesc ? 'rotate-180' : 'rotate-0']"
                  />
                </button>
              </div>
            </div>
          </div>
          <!-- BODY -->
          <div v-if="data?.length && !isLoading" class="table-row-group">
            <div
              v-for="row in data"
              :key="row"
              class="table-row border bg-white last:border-0"
              :class="areRowsClickable ? 'cursor-pointer hover:bg-gray-100' : ''"
              @click="handleRowClick(row)"
            >
              <div
                v-for="cell in visibleCols"
                :key="cell.displayName"
                class="table-cell whitespace-nowrap border-b border-r px-3 py-2 last:border-r-0"
              >
                <!-- VIRTUAL COLUMN -->
                <component :is="cell.component(row, emit)" v-if="!('accessor' in cell) && cell.component !== undefined" />
                <!-- NORMAL COLUMN -->
                <span v-else-if="'accessor' in cell && cell.component === undefined && row[cell.accessor] !== null">
                  {{ row[cell.accessor] }}
                </span>
                <!-- CUSTOM COLUMN -->
                <component
                  :is="cell.component(row[cell.accessor])"
                  v-else-if="'accessor' in cell && cell.component !== undefined"
                />
                <!-- EMPTY STATE -->
                <span v-else>---</span>
              </div>
            </div>
          </div>
        </div>
    

    Don't know why that worked tho! but it seems like Safari doesn't support <table> tags to be clickable