# Scroll Nav

Scroll Nav is a versatile and lightweight JavaScript plugin designed to enhance navigation menus with smooth scrolling capabilities.

[![npm](https://img.shields.io/badge/npm-v4.2.0-blue)](https://www.npmjs.com/package/@preline/scroll-nav) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![Demo](https://img.shields.io/badge/demo-online-brightgreen)](https://preline.co/plugins/scroll-nav.html)

## Contents

- [Overview](#overview)
- [Installation](#installation)
- [Basic usage](#basic-usage)
- [Configuration Options](#configuration-options)
- [JavaScript API](#javascript-api)
- [Common Patterns](#common-patterns)
- [License](#license)

## Overview

The Scroll Nav component provides horizontal scrolling navigation with previous/next buttons and automatic centering. It's ideal for navigation menus with many items that need to be scrolled horizontally.

**Key Features:**
- Horizontal scrolling navigation
- Previous/next navigation buttons
- Automatic centering of active items
- Programmatic control via JavaScript API
- Smooth scrolling animations
- Current state tracking

## Installation

To get started, install Scroll Nav plugin via npm, else you can skip this step if you are already using Preline UI as a package.

```bash
npm i @preline/scroll-nav
```

### CSS

Use [`@source`](https://tailwindcss.com/docs/functions-and-directives#source-directive) to register the plugin's JavaScript path for Tailwind CSS scanning, then [`@import`](https://tailwindcss.com/docs/functions-and-directives#import-directive) the plugin's CSS files into your Tailwind CSS file.

```css
@import "tailwindcss";

/* @preline/scroll-nav */
@source "../node_modules/@preline/scroll-nav/*.js";
@import "./node_modules/@preline/scroll-nav/variants.css";
@import "./node_modules/@preline/scroll-nav/theme.css";
```

### JavaScript

Include the JavaScript that powers the interactive elements near the end of your `</body>` tag:

```html
<script src="./node_modules/@preline/scroll-nav/index.js"></script>
```

### Manual Initialization

Use the `non-auto` entry if you need manual initialization. In this mode, automatic initialization on page load is not included, so the component should be initialized explicitly.

```html
<script type="module">
  import HSScrollNav from "@preline/scroll-nav/non-auto.mjs";

  new HSScrollNav(document.querySelector("#scroll-nav"));
</script>
```

### Via Bundler

When using a bundler (Vite, webpack, etc.), import the plugin directly as an ES module.

`@preline/scroll-nav` is the auto-init entry: it scans the DOM and initializes matching elements automatically.

```js
import "@preline/scroll-nav";
```

`@preline/scroll-nav/non-auto` is the manual entry: use it when you want explicit control over when initialization happens, either via `autoInit()` or by creating a specific instance yourself.

```js
import HSScrollNav from "@preline/scroll-nav/non-auto";

HSScrollNav.autoInit();

// Or initialize a specific element manually
const el = document.querySelector("#scroll-nav");
if (el) new HSScrollNav(el);
```

### TypeScript

This package ships with TypeScript type definitions. No additional `@types/` package is needed.

## Basic usage

The following example demonstrates the minimal HTML structure required for a scroll nav component. This is a base template without custom styling - you can apply your own CSS classes and styles as needed. The navigation items scroll horizontally with previous/next buttons.

```html
<div data-hs-scroll-nav class="relative px-6">
  <button type="button" class="hs-scroll-nav-prev">Previous</button>

  <nav class="hs-scroll-nav-body flex flex-nowrap overflow-x-auto snap-x snap-mandatory">
    <a class="snap-start" href="#">Electronics</a>
    <a class="snap-start" href="#">Clothing</a>
    <a class="snap-start" href="#">House & Garden</a>
    <a class="snap-start" href="#">Baby Care</a>
    <a class="snap-start" href="#">Home appliances</a>
    <a class="snap-start" href="#">Sports & Fitness</a>
    <a class="snap-start" href="#">Constraction & Renovation</a>
    <a class="snap-start" href="#">Food</a>
    <a class="snap-start" href="#">Pharmacy</a>
    <a class="snap-start" href="#">Pet Products</a>
    <a class="snap-start" href="#">Books</a>
    <a class="snap-start" href="#">Tourism, fishing, hunting</a>
    <a class="snap-start" href="#">Furniture</a>
    <a class="snap-start" href="#">Jewelery</a>
    <a class="snap-start" href="#">Accessories</a>
    <a class="snap-start" href="#">Games & Consoles</a>
    <a class="snap-start" href="#">Stationery</a>
    <a class="snap-start" href="#">Digital Goods</a>
    <a class="snap-start" href="#">Music</a>
  </nav>

  <button type="button" class="hs-scroll-nav-next">Next</button>
</div>
```

**Structure Requirements:**
- `data-hs-scroll-nav`: Required on the container element
- `hs-scroll-nav-prev`: Required class on the previous button
- `hs-scroll-nav-next`: Required class on the next button
- `hs-scroll-nav-body`: Required class on the scrollable navigation container
- Navigation items inside the scrollable container

**Initial State:**
- Navigation items are visible
- Previous/next buttons are enabled/disabled based on scroll position
- Active item can be centered automatically if `autoCentering` is enabled

## Configuration Options

### Data Options

Data options are specified in the `data-hs-scroll-nav` attribute.

| Attribute | Target Element | Type | Default | Description |
| --- | --- | --- | --- | --- |
| `data-hs-scroll-nav` | Container | - | - | Activate a Scroll Nav by specifying on an element. Should be added to the container. |
| `:autoCentering` | Inside `data-hs-scroll-nav` | boolean | `false` | Defines whether the Scroll Nav should align with the active item when the window loads. When `true`, the active item is automatically centered on page load. |

**Example:**
```html
<div data-hs-scroll-nav='{
  "autoCentering": true
}'>
  <!-- Navigation structure -->
</div>
```

### Required CSS Classes

These classes define the structure and must be present for the scroll nav to function.

| Class | Required On | Purpose |
| --- | --- | --- |
| `hs-scroll-nav-prev` | Previous button | Identifies the previous navigation button |
| `hs-scroll-nav-next` | Next button | Identifies the next navigation button |
| `hs-scroll-nav-body` | Scrollable container | Identifies the scrollable navigation container |

### Tailwind Modifiers

| Name | Description |
| --- | --- |
| `hs-scroll-nav-active:*` | The class is applied to the navigation item to style the currently active element. |
| `hs-scroll-nav-disabled:*` | The class is added to the prev/next buttons for style the disabled state. |

## JavaScript API

The `HSScrollNav` object is available in the global `window` object after the plugin is loaded.

### Instance Methods

These methods are called on a scroll nav instance.

| Method | Parameters | Return Type | Description |
| --- | --- | --- | --- |
| `getCurrentState()` | None | `IScrollNavCurrentState` | Retrieves the currently visible first, last, and center elements within the scrollable navigation container. Returns an object with `first`, `last`, and `center` properties. |
| `goTo(el, cb)` | `el`: `Element` (target element)<br>`cb`: `Function` (optional callback) | `void` | Smoothly scrolls the navigation container to bring the specified element into view. The callback function is executed after scrolling completes. |
| `centerElement(el, behavior)` | `el`: `HTMLElement` (target element)<br>`behavior`: `ScrollBehavior` (optional, `"auto"` \| `"smooth"`) | `void` | Scrolls the navigation container to position the specified element at the center of the visible area. Default behavior is `"smooth"`. |
| `destroy()` | None | `void` | Destroys the scroll nav instance, removes all generated markup, classes, and event listeners. Use when removing scroll nav from DOM. |

### Static Methods

These methods are called directly on the `HSScrollNav` class.

| Method | Parameters | Return Type | Description |
| --- | --- | --- | --- |
| `HSScrollNav.getInstance(target, isInstance)` | `target`: `HTMLElement \| string` (CSS selector)<br>`isInstance`: `boolean` (optional) | `HTMLElement \| { id: string \| number, element: HSScrollNav } \| null` | Returns the scroll nav instance or element associated with the target. If `isInstance` is `true`, returns collection item object `{ id, element }` where `element` is the `HSScrollNav` instance. If `isInstance` is `false` or omitted, returns the DOM element (`HTMLElement`). Returns `null` if scroll nav instance is not found. |

### Usage Examples

**Example 1: Getting current state**
```javascript
// Get the scroll nav instance
const instance = HSScrollNav.getInstance('#hs-scroll-nav', true);

if (instance) {
  const { element } = instance;
  // Get current state
  const state = element.getCurrentState();

  console.log('First visible:', state.first);
  console.log('Last visible:', state.last);
  console.log('Center visible:', state.center);
}
```

**Example 2: Scrolling to an element**
```javascript
const instance = HSScrollNav.getInstance('#hs-scroll-nav', true);

if (instance) {
  const { element } = instance;
  const targetLink = document.querySelector('#hs-e-commerce-link');

  // Scroll to element
  element.goTo(targetLink, () => {
    console.log('Scrolled to element!');
    // Perform actions after scrolling
  });
}
```

**Example 3: Centering an element**
```javascript
const instance = HSScrollNav.getInstance('#hs-scroll-nav', true);

if (instance) {
  const { element } = instance;
  const targetLink = document.querySelector('#hs-e-commerce-link');

  // Center element
  element.centerElement(targetLink, 'smooth');
}
```

**Example 4: Destroying scroll nav instance**
```javascript
const instance = HSScrollNav.getInstance('#hs-scroll-nav', true);

if (instance) {
  const { element } = instance;
  const removeBtn = document.querySelector('#hs-remove-btn');

  removeBtn.addEventListener('click', () => {
    // Clean up before removing from DOM
    element.destroy();
    // Now safe to remove the element
    document.querySelector('#hs-scroll-nav').remove();
  });
}
```

## Common Patterns

### Pattern 1: Auto-centering Active Item

Automatically center the active item on page load.

```html
<div data-hs-scroll-nav='{
  "autoCentering": true
}'>
  <!-- Navigation structure -->
</div>
```

### Pattern 2: Programmatic Navigation

Control navigation programmatically.

```html
<div id="hs-scroll-nav-first" data-hs-scroll-nav>
  <!-- Navigation structure -->
</div>

<script>
  const instance = HSScrollNav.getInstance('#hs-scroll-nav-first', true);
  if (instance) {
    const { element } = instance;
    // Scroll to specific item
    const item = document.querySelector('#hs-item-electronics');
    
    element.goTo(item);
  }
</script>
```

## License

Copyright (c) 2024 Htmlstream.

Licensed under the [MIT License](https://opensource.org/licenses/MIT).
