npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-scroll-snap-tabs

v1.0.4

Published

Scroll Snap Tabs for React.js is a versatile and interactive component designed to provide a seamless tab navigation experience, specifically optimized for touch devices

Downloads

32

Readme

React Scroll Snap Tabs

React Scroll Snap Tabs for React.js is a versatile and interactive component designed to provide a seamless tab navigation experience, specifically optimized for touch devices. With its intuitive touch gestures and responsive design, this component ensures effortless scrolling and tab switching on mobile devices and tablets. Users can easily swipe between tabs, making it a breeze to navigate through the content. The component is thoughtfully designed to accommodate the unique interaction patterns of touch devices, offering a user-friendly experience for both touch and non-touch environments. Developers can seamlessly integrate this touch-friendly component into their React.js applications, providing a consistent and enjoyable tabbed interface across all devices.

NPM JavaScript Style Guide

Demo 1

Demo 2

Demo 3

Table Of Contents

  1. Install
  2. Basic Usage
  3. Advanced Usage
  4. Props
  5. Nav Component Props
  6. Link Component Props
  7. Content Component Props
  8. Pane Component Props
  9. Easing Functions
  10. onIndicatorMove Event
  11. How Indicator Works

Install

npm i react-scroll-snap-tabs

Basic Usage

Note that, in order to prevent unexpected behaviors, the order of links and panes should exactly match based on their eventKeys.

import React from 'react'

import Tabs from 'react-scroll-snap-tabs'
import 'react-scroll-snap-tabs/dist/index.css'

const App = () => {
  return (
    <div style={{ width: '400px', height: '100vh', border: '1px solid gray' }}>
      <Tabs eventKeys={['Tab 1', 'Tab 2']}>
        <Tabs.Content paneStyle={{ border: '1px solid gray' }}>
          <Tabs.Pane eventKey='Tab 1'>Content 1</Tabs.Pane>
          <Tabs.Pane eventKey='Tab 2'>Content 2</Tabs.Pane>
        </Tabs.Content>
      </Tabs>
    </div>
  )
}

export default App

Result:

BasicScrollSnapTabs2

Advanced Usage

import React from 'react'

import Tabs from 'react-scroll-snap-tabs'
import 'react-scroll-snap-tabs/dist/index.css'

const App = () => {
  const width = 10
  const onIndicatorMove = (e) => {
    const indicator = e.target
    const timing = (t) => -12 * (t - 0.5) * (t - 0.5) + 4
    const progress = timing(e.progress)
    indicator.style.width = progress * width + 'px'
  }

  return (
    <div style={{ width: '400px', height: '100vh', backgroundColor: '#333' }}>
      <Tabs style={{ borderRight: '1px solid gray' }} snapDuration={300} defaultKey='tab3'>
        <Tabs.Nav
          activeLinkStyle={{ color: 'white' }}
          linkStyle={{ whiteSpace: 'nowrap' }}
          indicatorStyle={{
            borderRadius: '3px',
            width: width + 'px',
            maxWidth: '100%',
            backgroundColor: 'orange'
          }}
          style={{ color: 'gray', backgroundColor: 'black', borderRadius: '5px' }}
          onIndicatorMove={onIndicatorMove}
        >
          <Tabs.Link eventKey='tab1'>Tab 1</Tabs.Link>
          <Tabs.Link eventKey='tab2'>Very Long Tab 2</Tabs.Link>
          <Tabs.Link eventKey='tab3'>Tab 3</Tabs.Link>
          <Tabs.Link eventKey='tab4'>Very Long Tab 4</Tabs.Link>
          <Tabs.Link eventKey='tab5'>Very Long Tab 5</Tabs.Link>
        </Tabs.Nav>
        <Tabs.Content
          style={{ overscrollBehaviorY: 'contain' }}
          paneStyle={{ minHeight: '100%', minWidth: '100%' }}
        >
          <Tabs.Pane eventKey='tab1'>
            <CustomComponent color='white'>Content 1</CustomComponent>
          </Tabs.Pane>
          <Tabs.Pane eventKey='tab2'>
            <CustomComponent color='white'>Content 2</CustomComponent>
          </Tabs.Pane>
          <Tabs.Pane eventKey='tab3'>
            <CustomComponent color='white'>Content 3</CustomComponent>
          </Tabs.Pane>
          <Tabs.Pane eventKey='tab4'>
            <CustomComponent color='white'>Content 4</CustomComponent>
          </Tabs.Pane>
          <Tabs.Pane eventKey='tab5'>
            <CustomComponent color='white'>Content 5</CustomComponent>
          </Tabs.Pane>
        </Tabs.Content>
      </Tabs>
    </div>
  )
}

function CustomComponent({ children, color }) {
  return (
    <div
      style={{
        backgroundColor: 'transparent',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        fontStyle: 'bold',
        fontSize: '3vw',
        width: '100%',
        height: '100%',
        color
      }}
    >
      {children}
    </div>
  )
}

export default App

Result:

AdvancedScrollSnapTabs

Props

| Name | Type | Default | Description | | :--------------------- | :--------------- | :----------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | activeLinkClass | string | | Class name to be applied to the active link in the navigation. | | activeLinkStyle | object | {color: '#5A90E4'} | Style to be applied to the active link in the navigation. | | defaultKey | string(eventKey) | first tab's event | default event key to snap to the corresponding tab on load | | easing | string | func | "ease-out" | Sets the easing function for snap animation. The value should be either "ease-in", "ease-out", or "ease-in-out". If a random string value is provided, the default easing function will be (t) => t (linear). read more | | eventKeys | [string] | | Manually configure and customize all events without the need for a Nav component | | indicatorClass | string | | Assigns a class name to the indicator element. | | indicatorColor | string | "black" | Assigns the background color of the indicator element. | | indicatorSize | string | "100%" | Assigns the size of the indicator element. | | indicatorStyle | object | | Style to be applied to the indicator element | | indicatorParentClass | string | | Assigns a class name to the indicator's parent element. | | indicatorParentStyle | object | | Style to be applied to the indicator's parent element | | layout | string | "veritical" | Sets the layout of the component. The value should be either "horizontal" or "vertical". If a random string value is provided, the default layout will be "vertical" | | linkClass | string | | Assigns a class name to all of the link components in the navigation component. | | linkStyle | object | | Applies styles to all of the link components in the navigation component. | | onIndicatorMove | func | | When the indicator element moves, the onIndicatorMove callback function is triggered along with the movement. | | scrollIntoViewEasing | string | func | "ease-out" | Sets the easing function for scroll into view animation. The value should be either "ease-in", "ease-out", or "ease-in-out". If a random string value is provided, the default easing function will be (t) => t (linear). read more | | scrollIntoViewDuration | number | 250 | Sets the duration in ms for the scroll into view animation. | | scrollIntoViewOffset | number | 100 | Sets an additional scroll offset for the scroll into view animation. | | snapDuration | number | 250 | Sets the duration in ms for the scroll snap animation. | | snapThreshold | number | 30 | Sets the threshold for the snap action to start. If the threshold value is exceeded, it snaps to the next item; otherwise, it snaps to the current item. | | swipeThreshold | number | 200 | Sets the threshold for the snap action to start on touch devices. When a swipe action is performed, the algorithm calculates an inertial value. If the calculated value exceeds the swipe threshold value, it snaps to the next item; otherwise, it snaps to the current item. |

Nav Component Props

In the navigation component, you can utilize the same props as described previously, which are as follows:

  • activeLinkClass
  • activeLinkStyle
  • eventKeys
  • indicatorClass
  • indicatorColor
  • indicatorSize
  • indicatorStyle
  • indicatorParentClass
  • indicatorParentStyle
  • linkStyle
  • linkClass
  • onIndicatorMove
  • scrollIntoViewEasing
  • scrollIntoViewDuration
  • scrollIntoViewOffset

Link Component Props

| Name | Type | Default | Description | | :---------- | :----- | :------ | :---------------------------------------------------------------------------- | | activeClass | string | | The class name to be applied to the link when it's active. | | activeStyle | object | | The style to be applied to the link when it is active. | | eventKey | string | | The event key that corresponds to the pane component with the same event key. |

Content Component Props

| Name | Type | Default | Description | | :-------- | :----- | :------ | :--------------------------------------------------------------------------- | | paneClass | string | | Assigns a class name to all of the pane components in the content component. | | paneStyle | object | | Applies styles to all of the pane components in the content component. |

Pane Component Props

| Name | Type | Default | Description | | :------- | :----- | :------ | :---------------------------------------------------------------------------- | | eventKey | string | | The event key that corresponds to the link component with the same event key. |

Easing Functions

You can use predefined easing functions by providing either "ease-in", "ease-out", or "ease-in-out" string values. If a random string value is provided, the default easing function will be (t) => t (linear). Alternatively, you can provide your own easing function that accepts a number argument between 0 and 1 and returns a number between 0 and 1. You can find more about easing functions on easings.net.

onIndicatorMove Event

When the indicator element moves, the onIndicatorMove callback function is triggered along with the movement.

Event Properties:

Event.progress

It is a fractional value between two snap points that ranges from 0 to 1. The current snap point, representing the current content, is 0, and the target snap point is 1.

Event.target

Returns the indicator element.

Event.isInteracting

Returns a boolean value indicating whether or not the user is interacting with the content area.

Example

import React from 'react'

import Tabs from 'react-scroll-snap-tabs'
import 'react-scroll-snap-tabs/dist/index.css'

const App = () => {
  const width = 10
  const onIndicatorMove = (e) => {
    const indicator = e.target
    const timing = (t) => -12 * (t - 0.5) * (t - 0.5) + 4
    const progress = timing(e.progress)
    indicator.style.width = progress * width + 'px'
  }

  return (
    <div style={{ width: '400px', height: '100vh', backgroundColor: '#333' }}>
      <Tabs
        style={{ borderRight: '1px solid gray' }}
        onIndicatorMove={onIndicatorMove}
        snapDuration={300}
        defaultKey='tab3'
      >
        <Tabs.Nav
          activeLinkStyle={{ color: 'white' }}
          linkStyle={{ whiteSpace: 'nowrap' }}
          indicatorStyle={{
            borderRadius: '3px',
            width: width + 'px',
            maxWidth: '100%',
            backgroundColor: 'orange'
          }}
          style={{ color: 'gray', backgroundColor: 'black', borderRadius: '5px' }}
        >
          <Tabs.Link eventKey='tab1'>Tab 1</Tabs.Link>
          <Tabs.Link eventKey='tab2'>Very Long Tab 2</Tabs.Link>
          <Tabs.Link eventKey='tab3'>Tab 3</Tabs.Link>
          <Tabs.Link eventKey='tab4'>Very Long Tab 4</Tabs.Link>
          <Tabs.Link eventKey='tab5'>Very Long Tab 5</Tabs.Link>
        </Tabs.Nav>
        <Tabs.Content
          style={{ overscrollBehaviorY: 'contain' }}
          paneStyle={{ minHeight: '100%', minWidth: '100%' }}
        >
          <Tabs.Pane eventKey='tab1'>
            <CustomComponent color='white'>Content 1</CustomComponent>
          </Tabs.Pane>
          <Tabs.Pane eventKey='tab2'>
            <CustomComponent color='white'>Content 2</CustomComponent>
          </Tabs.Pane>
          <Tabs.Pane eventKey='tab3'>
            <CustomComponent color='white'>Content 3</CustomComponent>
          </Tabs.Pane>
          <Tabs.Pane eventKey='tab4'>
            <CustomComponent color='white'>Content 4</CustomComponent>
          </Tabs.Pane>
          <Tabs.Pane eventKey='tab5'>
            <CustomComponent color='white'>Content 5</CustomComponent>
          </Tabs.Pane>
        </Tabs.Content>
      </Tabs>
    </div>
  )
}

function CustomComponent({ children, color }) {
  return (
    <div
      style={{
        backgroundColor: 'transparent',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        fontStyle: 'bold',
        fontSize: '3vw',
        width: '100%',
        height: '100%',
        color
      }}
    >
      {children}
    </div>
  )
}

export default App

How Indicator Works

The tabs include an indicator section that consists of two elements: an indicator and its parent. The parent elemet dynamically adjusts its position based on the active tab, while the indicator represents the actual visible part.

When the user scrolls through the content area, if the layout is 'vertical', the indicator parent adjusts its left and width values to align with the target link element's left and width values. If the layout is 'horizontal', it aligns its top and height values.

Example

import React from 'react'

import Tabs from 'react-scroll-snap-tabs'
import 'react-scroll-snap-tabs/dist/index.css'

const App = () => {
  return (
    <div style={{ width: '400px', height: '100vh', border: '1px solid gray' }}>
      <Tabs
        indicatorParentClass='indicator-parent'
        indicatorParentStyle={{ border: '1px solid red' }}
        indicatorClass='indicator'
        indicatorStyle={{ maxWidth: '75%' }}
        eventKeys={['Tab 1', 'Very Long Tab 2']}
      >
        <Tabs.Content paneStyle={{ border: '1px solid gray' }}>
          <Tabs.Pane eventKey='Tab 1'>Content 1</Tabs.Pane>
          <Tabs.Pane eventKey='Very Long Tab 2'>Content 2</Tabs.Pane>
        </Tabs.Content>
      </Tabs>
    </div>
  )
}

export default App

To provide a visual representation of this behavior, consider the following HTML code, which showcases a rendered indicator parent and indicator elements in a vertical layout application:

<div
  class="indicator-parent"
  style="position: absolute; bottom: 0px; border: 1px solid red; left: 53px; width: 128px;"
>
  <div
    class="indicator"
    style="height: 100%; margin: auto; min-height: 3px; background-color: black; max-width: 75%;"
  ></div>
</div>

Result:

IndicatorScrollSnapTabs2

In the provided code, the indicator parent element is represented by the <div> with the class name 'indicator-parent'. It is positioned absolutely and has a red border. Its left and width values are adjusted dynamically based on the corresponding link element's left and width values.

Inside the indicator parent, the indicator element is represented by the <div> with the class name 'indicator'. The background color is black.

License

MIT © aacar947