Home > Web Front-end > JS Tutorial > Create a Resizable Navigation with Stimulus

Create a Resizable Navigation with Stimulus

DDD
Release: 2024-09-13 06:17:10
Original
941 people have browsed it

This article was originally published on Rails Designer—UI components library for Rails app, built with ViewComponent, designed with Tailwind CSS and enhanced with Hotwire.


If your app has a sidebar navigation, which is quite common with most screens being wide enough to support these days, making it resizable might be a great feature to add. Giving this customization allows your users to tweak the screen for the task at hand. Maybe they want to focus on writing their next big piece or maybe they split their screen, making the default width a bit too wide.

Create a Resizable Navigation with Stimulus

Whatever the reason, resizing the sidebar navigation (or any other component) is easy with JavaScript and thus with Stimulus. Let's dive right in. Let's set up the basics in HTML:

<main data-controller="resizer" class="flex">
  <nav data-resizer-target="container" class="relative w-1/6">
    <!-- Imagine some nav items here -->
  </nav>

  <div class="w-5/6">
    <p>Content for your app here</p>
  </div>
</main>
Copy after login

Above HTML is using Tailwind CSS classes, but that's not required for this example. You can of course style it however you like.

Now the stimulus controller. As you noticed from above the handler (the element that can be dragged to resize) is not added in the HTML, it will instead be injected with JS.

import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="resizer"
export default class extends Controller {
  static targets = ["container"];
  static values = {
    resizing: { type: Boolean, default: false },
    maxWidth: { type: Number, default: 360 } // in px
  };

  connect() {
    this.containerTarget.insertAdjacentHTML("beforeend", this.#handler);
  }

  // private

  get #handler() {
    return `
      <span
        data-action="mousedown->resizer#setup"
        class="absolute top-0 w-1 h-full bg-gray-200 -right-px cursor-col-resize hover:bg-gray-300"
      ></span>
    `
  }
}
Copy after login

This will inject the handler next to the nav-element (absolute positioned). It also has a action to fire setup() on the mousedown event. Let's add it.

export default class extends Controller {
  // …
  connect() {
    this.containerTarget.insertAdjacentHTML("beforeend", this.#handler);

    this.resize = this.#resize.bind(this);
    this.stop = this.#stop.bind(this);
  }

  setup() {
      this.resizingValue = true;

      document.addEventListener('mousemove', this.resize);
      document.addEventListener('mouseup', this.stop);
  }
  // …
}
Copy after login

What's going on here? Why not add the #resize() and #stop() on respectively mousemove and mouseup events. This is to ensure that this refers to the controller instance when resize and stop are called as event listeners, preserving access to controller properties and methods.

Let's add the private functions #resize() and #stop().

export default class extends Controller {
  // …

  // private

  #resize(event) {
    if (!this.resizingValue) return;

    const width = event.clientX - this.containerTarget.offsetLeft;

    if (width <= this.maxWidthValue) {
      this.containerTarget.style.width = `${width}px`;
    } else {
      this.containerTarget.style.width = `${this.maxWidthValue}px`;
    }
  }

  #stop() {
    this.resizingValue = false;

    document.removeEventListener('mousemove', this.resize);
    document.removeEventListener('mouseup', this.stop);
  }

  // …
}
Copy after login

The #resize() function calculates the new width of the container based on the mouse position (event.clientX) and updates the container's width, ensuring it doesn't exceed the maximum allowed width (set in values). The #stop() function stops the resizing process by setting the resizingValue to false and removing the event listeners.

If you head over to your browser, you are now able to resize the browser and not make it wider than the value set as maxWidth (360px by default).

Awsome! ? That's all you need to resize an element in your app using Stimulus. From here you can improve by storing the value in the user's settings (eg. via Redis) to be the same across browsers or store it in browser's LocalStorage to store it for that session (Rails Designer helps you by providing JS utilities for that).

The above is the detailed content of Create a Resizable Navigation with Stimulus. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template