Invalid hook call on save, not edit when using swiper slider

You’ve misunderstood the purpose of the save component. The goal of the save component is not to return an interactive React component, it’s to return something that can be converted into static HTML and saved in the database as a string in the post content.

Since only the HTML gets saved, it’s your responsibility to load javascript on the frontend that finds this HTML and converts it into a Swiper slider.

So you should not attempt to do any of the following in the save component, directly or indirectly via a library:

  • event listeners
  • react state
  • callbacks/effects/HTTP requests/etc

A save component can even be ran when no saving is occurring, for example when validating a block by comparing the saved block to the save component.

So with this in mind, it makes no sense to use <Swiper> or <SwiperSlide> components here.

Instead, follow the Swiper documentation and generate actual HTML instead:

<!-- Slider main container -->
<div class="swiper">
  <!-- Additional required wrapper -->
  <div class="swiper-wrapper">
    <!-- Slides -->
    <div class="swiper-slide">Slide 1</div>
    <div class="swiper-slide">Slide 2</div>
    <div class="swiper-slide">Slide 3</div>
    ...
  </div>
  <!-- If we need pagination -->
  <div class="swiper-pagination"></div>

  <!-- If we need navigation buttons -->
  <div class="swiper-button-prev"></div>
  <div class="swiper-button-next"></div>

  <!-- If we need scrollbar -->
  <div class="swiper-scrollbar"></div>
</div>

https://swiperjs.com/get-started#add-swiper-html-layout

Adjust it for JSX and save it that way.


As an aside, the way the Swiper library detects the slides in the <Swiper> component is by inspecting the virtual dom and looking for direct descendants of type <SwiperSlide>. This means it cannot find the slides if you use Slide blocks. This means having user configurable slides is not possible in Gutenberg because of the higher order components used to provide block information. It’s not possible to have nested blocks this way. Swiper will interpret child blocks as additional HTML to append after the slider, even if they’re slides or <SwiperSlide> components.