Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Hooks & Utilities

useScrollState

Hooks & Utilities

useScrollState React hook in TypeScript

useScrollEdgesuseSelection
Live props
Options
hideOnScroll
hideDistance56px
hideOffset0px
snap
revealAtEnd
scrolledThreshold1px
disabled
  1. Home
  2. Components
  3. Hooks & Utilities
  4. useScrollState
Pro

useScrollState React hook in TypeScript

v1.0.0·Added in 1.0.0

A React scroll position hook: offset, progress and hide-on-scroll state for the window or a container, as motion values without re-renders.

Scroll the feed in the phone frame: the top bar slides away with your finger as you scroll down and comes back the moment you scroll up, then settles fully shown or hidden when you stop. The progress line under it fills as you read, the large title fades into the bar, and a back-to-top button appears once you pass the threshold. The readout shows direction, scrolled and hidden flipping without a render per frame.

useScrollState is a Pro React hook in the React hooks and utilities category, written in TypeScript for React 19. It installs as source with npx wingo-ui@latest add use-scroll-state, together with useMediaQuery and Motion presets and the npm package motion.

Add to a project

Requirements: React 19, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add use-scroll-state

useScrollState is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import useScrollState from @/hooks/use-scroll-state.

import { motion, useTransform } from "motion/react"
import { useScrollState } from "@/hooks/use-scroll-state"
import { cn } from "@/lib/utils"

export function AppHeader() {
  const { hideProgress, scrolled } = useScrollState({ hideOnScroll: true, hideDistance: 56 })
  const y = useTransform(hideProgress, [0, 1], [0, -56])

  return (
    <motion.header
      style={{ y }}
      className={cn(
        "sticky top-0 z-sticky flex h-14 items-center bg-background/80 px-4 backdrop-blur-xl",
        scrolled && "border-b border-foreground/10",
      )}
    >
      <h1 className="text-[17px] font-semibold">Listings in New York</h1>
    </motion.header>
  )
}

API

  • hideOnScrolldefault false
    boolean

    useScrollState(options?): track hideProgress and hidden for a bar that slides away while you scroll down. Off by default, so hooks that only read the offset do no extra work.

  • hideDistancedefault 56
    number

    Pixels of scrolling that take a bar from shown to hidden, usually the bar's own height, so it moves 1:1 with the content.

  • hideOffsetdefault 0
    number

    The bar never hides above this offset, e.g. while a page header is still on screen. It can always come back.

  • snapdefault true
    boolean

    After scrolling stops, a half-hidden bar settles to shown or hidden on the snappy spring.

  • revealAtEnddefault true
    boolean

    Bring the bar back at the very end of the content, where nothing is left to uncover.

  • scrolledThresholddefault 1
    number

    scrolled turns true past this many pixels: 1 for a header hairline, 400 for a back-to-top button.

  • target
    HTMLElement | Window | RefObject<HTMLElement | null> | null

    What to watch. Default: the nearest ScrollContainerProvider, else the window. A ref is read after mount; pass the element itself when it can change.

  • disableddefault false
    boolean

    Stops listening; the values keep their last state.

  • returns
    { offset: MotionValue<number>; progress: MotionValue<number>; hideProgress: MotionValue<number>; direction: "up" | "down" | null; scrolled: boolean; hidden: boolean; atEnd: boolean; scrollTo(top, { smooth? }): void }

    offset (px, negative during an iOS bounce), progress (0 to 1) and hideProgress (0 shown to 1 hidden, following the finger) are motion values: feed them to useTransform and style. direction, scrolled, hidden and atEnd re-render only when they flip. scrollTo is smooth unless the user prefers reduced motion; under reduced motion hideProgress only ever jumps between 0 and 1.

Parts

  • ScrollContainerProvider

    component

    Declares the element that scrolls for everything inside it (an app shell's content area, a demo box, a phone frame). Keep the element in state through a callback ref so the children update once it mounts. Props: ({ value: HTMLElement | null; children }) => JSX.Element.

  • useScrollContainer

    hook

    The nearest provided scroll container, or null for the window. Scroll spies use it as their IntersectionObserver root. Signature: () => HTMLElement | null.

  • findScrollParent

    function

    The nearest vertically scrolling ancestor of an element, or null for the window. Signature: (element) => HTMLElement | null.

  • scrollToOffset

    function

    Scrolls an element or the window to an offset outside React, instant under reduced motion. Signature: (target, top, smooth?) => void.

  • ScrollContainerProviderProps

    type

    { value: HTMLElement | null; children?: ReactNode }.

  • ScrollTarget

    type

    What target accepts: HTMLElement | Window | RefObject<HTMLElement | null> | null | undefined.

  • ScrollDirection

    type

    "up" | "down", the last scroll direction.

  • UseScrollStateOptions

    type

    The options object: target, scrolledThreshold, hideOnScroll, hideDistance, hideOffset, revealAtEnd, snap and disabled.

  • ScrollState

    type

    The return value: offset, progress and hideProgress motion values, the direction, scrolled, hidden and atEnd flags, and scrollTo.

Examples

Reading progress

A bar that fills as you read an article in its own scroll container, through the target option.

Bottom actions that step aside

hideOnScroll slides the action bar down while you scroll the list and brings it back on the way up.

Dependencies

motionuse-media-querymotion

Files

  • hooks/use-scroll-state.ts

FAQ

Is the useScrollState hook free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install useScrollState?

Run npx wingo-ui@latest add use-scroll-state. It also adds the Wingo UI items it builds on (useMediaQuery and Motion presets) and the npm package motion. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/use-scroll-state.

See also

Scroll ProgressBack To TopuseScrollEdgeshookLarge Title HeaderMotion presetslib

Used in

Hero HeaderBottom Tab BarSticky CTA BarListing gridApp ShellBack To TopPaginationTable Of ContentsTopbarVirtual ListPage HeaderSettings Layout

and 5 more.

More React hooks and utilities

useSelectionhookuseShortcuthookuseStickToBottomhookAI ChatlibChart kitlibCommercelib
All 36 React hooks and utilities

Articles using this component

  • React Collapsing Header: iOS Large Title and Photo Hero

    Mobile UI in React · Oct 16, 2026 · 8 min read

PrevioususeScrollEdgesNext useSelection
Listings

Listings

New York and nearby · 1,240 listings

direction: nonescrolled: falsehidden: falseatEnd: false
  • Trek city bike

    $1,200

    Brooklyn, Park Slope · Sep 23, 2026

  • Sleeper sofa, 3 seats

    $850

    Queens, Astoria · Sep 23, 2026

  • MacBook Air M2, 256 GB

    $4,300

    Manhattan, Chelsea · Sep 22, 2026

  • iPhone 13, 128 GB, blue

    $1,850

    Brooklyn, Williamsburg · Sep 22, 2026

  • 2 bedroom apartment, renovated

    $489,000

    Jersey City, Downtown · Sep 21, 2026

  • Honda Civic 2019, 51,000 mi

    $38,500

    Hoboken, Uptown · Sep 21, 2026

  • 4 person tent, used once

    $420

    Bronx, Riverdale · Sep 20, 2026

  • Coworking desk, monthly

    $650

    Manhattan, SoHo · Sep 20, 2026

  • Kids bike, 20 inch

    $390

    Staten Island, St. George · Sep 19, 2026

  • Upholstered armchair, gray

    $300

    Brooklyn, Downtown · Sep 19, 2026

  • Dell 27 inch monitor, 4K

    $1,100

    Queens, Flushing · Sep 18, 2026

  • Samsung Galaxy S22, like new

    $1,650

    Newark, Ironbound · Sep 18, 2026

Turn on hideOnScroll to let the bar slide away.

hideOffset 0px · snap on · revealAtEnd on · scrolledThreshold 1px