Use Lock Body Scroll

A Rust/UI hook that locks and unlocks body scrolling, useful for modal dialogs, sheets, and overlays.

utilsdialog
  • Rust/UI Icons - CopyCopy Demo

Body Scroll Lock Demo

Try scrolling the page. Click the button to lock/unlock body scrolling.

Scroll Status:🔓 Unlocked
use leptos::prelude::*;

use crate::components::hooks::use_lock_body_scroll::use_lock_body_scroll;
use crate::components::ui::button::Button;
use crate::components::ui::card::{Card, CardContent, CardDescription, CardHeader, CardTitle};

#[component]
pub fn DemoUseLockBodyScroll() -> impl IntoView {
    let scroll_locked = use_lock_body_scroll(false);

    let toggle_scroll_lock = move |_| {
        scroll_locked.update(|locked| *locked = !*locked);
    };

    view! {
        <Card class="mx-auto w-full max-w-md">
            <CardHeader>
                <CardTitle>"Body Scroll Lock Demo"</CardTitle>
                <CardDescription>
                    "Try scrolling the page. Click the button to lock/unlock body scrolling."
                </CardDescription>
            </CardHeader>
            <CardContent class="space-y-4">
                <div class="flex justify-between items-center">
                    <span class="text-sm font-medium">"Scroll Status:"</span>
                    <span class="py-1 px-2 text-sm rounded-full">
                        {move || if scroll_locked.get() { "🔒 Locked" } else { "🔓 Unlocked" }}
                    </span>
                </div>

                <Button on:click=toggle_scroll_lock class="w-full">
                    {move || if scroll_locked.get() { "Unlock Body Scroll" } else { "Lock Body Scroll" }}
                </Button>
            </CardContent>
        </Card>
    }
}

Installation

You can run either of the following commands:

# cargo install ui-cli --force
ui add demo_use_lock_body_scroll
ui add use_lock_body_scroll

Update the imports to match your project setup.

Copy and paste the following code into your project:

components/ui/use_lock_body_scroll.rs

use leptos::prelude::*;

pub fn use_lock_body_scroll(initial_locked: bool) -> RwSignal<bool> {
    let locked = RwSignal::new(initial_locked);

    Effect::new(move |_| {
        if let Some(body) = window().document().and_then(|d| d.body()) {
            let overflow = if locked.get() { "hidden" } else { "" };
            let _ = body.style().set_property("overflow", overflow);
        }
    });

    locked
}

Update the imports to match your project setup.

Usage

use crate::components::hooks::use_lock_body_scroll::use_lock_body_scroll;
let scroll_locked = use_lock_body_scroll(false);

// Lock body scrolling
scroll_locked.set(true);

// Unlock body scrolling  
scroll_locked.set(false);