sectify
v1.0.0
Published
Section-based scroll navigation with snap transitions (lightweight, framework-agnostic)
Maintainers
Readme
Sectify
Framework-agnostic full-page section navigation for modern websites and apps.
Sectify provides:
- Wheel, keyboard, and touch/swipe navigation
- Vertical (
y) and horizontal (x) modes - Programmatic controls (
next,prev,goTo) - Active section state + classes
- Optional URL hash/anchor deep linking
- Optional navigation dots
- Scrollable-content aware behavior (lets inner scroll containers scroll naturally)
- Responsive layout updates with robust cleanup (
update,destroy)
Installation
npm install sectifyQuick Start
<div id="app">
<section class="page" data-sectify-anchor="home">Home</section>
<section class="page" data-sectify-anchor="features">Features</section>
<section class="page" data-sectify-anchor="pricing">Pricing</section>
</div>import { createFullpage } from "sectify";
const root = document.getElementById("app");
if (!root) throw new Error("Missing #app");
const sectify = createFullpage(root, {
selectors: { section: ".page" },
useUrlHash: true,
navigation: { enabled: true },
});createSectify is exported as an alias of createFullpage.
You can also inspect the canonical defaults:
import { SECTIFY_DEFAULT_OPTIONS } from "sectify";API
createFullpage(root, options?)
root: root container that contains sections (and optional header/footer)options: optional configuration object- returns
SectifyInstance
Options
type Axis = "y" | "x";
type SectifyDirection = "up" | "down" | "left" | "right" | "none";
interface ChangeEventPayload {
index: number;
previousIndex: number;
direction: SectifyDirection;
anchor?: string;
previousAnchor?: string;
}
interface SectifyOptions {
scrollingSpeed?: number; // alias of duration
duration?: number;
easing?: string;
autoScrolling?: boolean;
wheel?: boolean;
keyboardScrolling?: boolean; // alias of keyboard
keyboard?: boolean;
touchMouseDragging?: boolean; // alias of touch
dragAndMove?: boolean; // alias of touch
touch?: boolean;
loop?: boolean;
startIndex?: number;
axis?: Axis;
// Optional static layout blocks inside root
// In non-overlay mode, footer is treated as an extra snap step after the last section.
footerSizeRatio?: number; // default: 0.3 (30% of visible area)
footerOverlayOnLastSection?: boolean; // default: false
selectors?: {
section?: string;
header?: string;
footer?: string;
};
// Input / behavior controls
ignoreWheelOn?: string;
normalScrollElements?: string; // alias of ignoreWheelOn
scrollOverflow?: boolean; // alias of allowScrollWithinSections
allowScrollWithinSections?: boolean;
scrollableSelector?: string;
wheelMinDelta?: number;
wheelCooldown?: number;
touchSensitivity?: number; // alias of touchMinSwipe
touchMinSwipe?: number;
lockBodyScroll?: boolean;
// Section state
activeClass?: string;
anchors?: string[];
lockAnchors?: boolean;
useUrlHash?: boolean;
animateAnchor?: boolean;
recordHistory?: boolean;
// Optional dots UI
navigation?: {
enabled?: boolean;
container?: HTMLElement | string;
clickable?: boolean;
itemClass?: string;
activeClass?: string;
};
// Callbacks similar to onLeave / afterLoad
afterRender?: () => void;
afterResize?: () => void;
onLeave?: (payload: ChangeEventPayload) => void;
afterLoad?: (payload: ChangeEventPayload) => void;
}Default behavior highlights
duration:700scrollingSpeed:700(alias ofduration)easing:"cubic-bezier(0.2, 0.8, 0.2, 1)"autoScrolling:trueaxis:"y"loop:falseallowScrollWithinSections:truescrollOverflow:true(alias ofallowScrollWithinSections)scrollableSelector:"[data-sectify-scroll], .sectify-scrollable"wheelMinDelta:10wheelCooldown:0.85(multiplied byduration)touchMinSwipe:50touchSensitivity:50(alias oftouchMinSwipe)activeClass:"sectify-active"lockAnchors:falseuseUrlHash:falseanimateAnchor:truerecordHistory:falselockBodyScroll:true
Instance
interface SectifyInstance {
next(): void;
prev(): void;
moveSectionDown(): void;
moveSectionUp(): void;
goTo(indexOrAnchor: number | string): void;
moveTo(indexOrAnchor: number | string): void;
silentMoveTo(indexOrAnchor: number | string): void;
setAllowScrolling(allowed: boolean): void;
setKeyboardScrolling(allowed: boolean): void;
update(): void;
reBuild(): void;
destroy(): void;
on(event: "change" | "leave" | "load", cb: (payload: ChangeEventPayload) => void): () => void;
readonly index: number;
}reBuild() is an alias of update().
Events and Callbacks
Sectify provides both callback options and event subscriptions:
onLeavecallback andleaveeventafterLoadcallback andloadeventchangeevent (fires on index changes)
const off = sectify.on("change", ({ previousIndex, index, direction, anchor }) => {
console.log({ previousIndex, index, direction, anchor });
});Anchors and Deep Linking
Use any of:
anchors: [...]in optionsdata-sectify-anchoron sections- section
id
Then enable hash syncing:
createFullpage(root, {
selectors: { section: ".page" },
useUrlHash: true,
});You can navigate programmatically by index or anchor:
sectify.goTo(2);
sectify.goTo("pricing");Scrollable Content Inside Sections
Sectify lets inner containers consume scroll before changing section when:
allowScrollWithinSectionsistrue(default), and- target is scrollable (native overflow or matching
scrollableSelector)
Example:
<section class="page">
<div class="sectify-scrollable" style="max-height: 60vh; overflow: auto;">
<!-- long content -->
</div>
</section>Navigation Dots
createFullpage(root, {
navigation: {
enabled: true,
clickable: true,
itemClass: "my-dot",
activeClass: "is-active",
// container: "#my-nav" // optional
},
});Sectify renders dot buttons with data-sectify-dot attributes and toggles active state automatically.
Header/Footer Pattern
You can keep a static header/footer inside the root while sections move within the track.
When footerOverlayOnLastSection is false (default), the footer behaves like an extra snap step:
- Reaching the last section and scrolling forward once more moves to the footer step.
- Footer height is controlled by
footerSizeRatio(for example0.3= 30% of visible area). - Scrolling back up returns to the last section.
- No fade/reveal delay is required; it behaves like continuous section movement.
When footerOverlayOnLastSection is true, the footer is layered above the last section instead of acting as a separate step.
createFullpage(root, {
selectors: {
header: ".site-header",
section: ".page",
footer: ".site-footer",
},
footerSizeRatio: 0.3,
footerOverlayOnLastSection: false,
});Example: footer as a 30% final step
createFullpage(root, {
selectors: {
section: ".page",
footer: ".site-footer",
},
footerSizeRatio: 0.3,
footerOverlayOnLastSection: false, // extra snap step after last section
});Updating and Destroying
- Call
update()after adding/removing sections or significant layout changes. - Call
destroy()to remove listeners, unwrap the internal track, and restore inline styles.
TypeScript
Type declarations are bundled in dist and exported via package exports.
License
MIT
