Skip to content

v-sticky

Make elements sticky when scrolling.

Since: 1.1.0

Usage

Basic

vue
<template>
  <div v-sticky>Sticky header</div>
</template>

With Offset

vue
<template>
  <div v-sticky="50">Sticky with 50px top offset</div>
</template>

With Options

vue
<template>
  <div v-sticky="{
    top: 60,
    zIndex: 1000,
    stickyClass: 'is-sticky'
  }">
    Custom sticky
  </div>
</template>

API

Types

typescript
interface StickyOptions {
  /** Top offset when sticky */
  top?: number | string
  /** Bottom offset when sticky */
  bottom?: number | string
  /** Z-index when sticky */
  zIndex?: number
  /** CSS class to add when sticky */
  stickyClass?: string
  /** Disable the directive */
  disabled?: boolean
  /** Callback when sticky state changes */
  onChange?: (isSticky: boolean) => void
  /** Custom scroll container */
  container?: string | Element | null
}

type StickyBinding = boolean | number | StickyOptions

Options

OptionTypeDefaultDescription
topnumber | string0Top offset when sticky
bottomnumber | string-Bottom offset when sticky
zIndexnumber100Z-index when sticky
stickyClassstring'v-sticky--fixed'CSS class when sticky
disabledbooleanfalseDisable the directive
onChangeFunction-Callback when sticky state changes
containerstring | Element-Custom scroll container

Examples

vue
<template>
  <nav v-sticky class="navbar">
    <a href="/">Home</a>
    <a href="/about">About</a>
    <a href="/contact">Contact</a>
  </nav>
</template>

<style>
.navbar {
  background: white;
  padding: 1rem;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.navbar.v-sticky--fixed {
  box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
</style>

Table Header

vue
<template>
  <table>
    <thead v-sticky="{ top: 60, zIndex: 10 }">
      <tr>
        <th>Name</th>
        <th>Email</th>
        <th>Status</th>
      </tr>
    </thead>
    <tbody>
      <!-- rows -->
    </tbody>
  </table>
</template>

Detect State Change

vue
<template>
  <div v-sticky="{
    top: 0,
    onChange: handleStickyChange
  }">
    {{ isSticky ? 'Sticky' : 'Normal' }}
  </div>
</template>

<script setup>
import { ref } from 'vue'

const isSticky = ref(false)

function handleStickyChange(sticky) {
  isSticky.value = sticky
}
</script>

Composable API

For programmatic use, you can use the useSticky composable:

typescript
import { useSticky } from 'directix'

const { isSticky, bind, stop } = useSticky({
  offsetTop: 0,
  onStick: (isSticky) => console.log('Sticky:', isSticky),
  disabled: false
})

// Bind to element
onMounted(() => bind(headerRef.value))

UseStickyOptions

OptionTypeDefaultDescription
offsetTopnumber | Ref<number>0Offset from top in pixels
onStick(isSticky: boolean) => void-Callback when stick state changes
disabledboolean | Ref<boolean>falseDisable sticky behavior

UseStickyReturn

PropertyTypeDescription
isStickyReadonly<Ref<boolean>>Whether the element is sticky
bind(element: HTMLElement) => () => voidBind sticky behavior to an element
stop() => voidStop observing

Example

vue
<script setup>
import { ref } from 'vue'
import { useSticky } from 'directix'

const headerRef = ref(null)
const { isSticky, bind } = useSticky({
  offsetTop: 60,
  onStick: (sticky) => console.log('Sticky:', sticky)
})

onMounted(() => bind(headerRef.value))
</script>

<template>
  <header ref="headerRef" :class="{ sticky: isSticky }">
    Navigation
  </header>
</template>

Code Generator

Quick Code Generator
<template>
  <div v-sticky="{ top: 0, zIndex: 100 }">
    <!-- Make elements sticky when scrolling. directive -->
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

// Configure your options here
const options = { top: 0, zIndex: 100 }
</script>

Released under the MIT License.