Base UI Adaptive Scroll Area
lina/lina-baseFreeComponent
A responsive scroll area that feel native on touch devices, offereing custom styling and enchanced interactions where it matter most.
Install it
npx shadcn@latest add https://lina.sameer.sh/r/lina-base.jsonSource
1"use client";23import * as React from "react";45import { ScrollArea as ScrollAreaPrimitive } from "@base-ui-components/react/scroll-area";67import { cn } from "@/lib/utils";89import { useTouchPrimary } from "@/hooks/use-has-primary-touch";1011type Mask = {12 top: boolean;13 bottom: boolean;14 left: boolean;15 right: boolean;16};1718export type ScrollAreaContextProps = {19 isTouch: boolean;20 type: "auto" | "always" | "scroll" | "hover";21};2223const ScrollAreaContext = React.createContext<ScrollAreaContextProps>({24 isTouch: false,25 type: "hover",26});2728const ScrollArea = React.forwardRef<29 React.ComponentRef<typeof ScrollAreaPrimitive.Root>,30 React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root> & {31 type?: "auto" | "always" | "scroll" | "hover";32 viewportClassName?: string;33 /**34 * `maskHeight` is the height of the mask in pixels.35 * pass `0` to disable the mask36 * @default 3037 */38 maskHeight?: number;39 maskClassName?: string;40 }41>(({ className, children, type = "hover", maskHeight = 30, maskClassName, viewportClassName, ...props }, ref) => {42 const [showMask, setShowMask] = React.useState<Mask>({43 top: false,44 bottom: false,45 left: false,46 right: false,47 });4849 const viewportRef = React.useRef<HTMLDivElement>(null);50 const isTouch = useTouchPrimary();5152 const checkScrollability = React.useCallback(() => {53 const element = viewportRef.current;54 if (!element) return;5556 const { scrollTop, scrollLeft, scrollWidth, clientWidth, scrollHeight, clientHeight } = element;57 setShowMask((prev) => ({58 ...prev,59 top: scrollTop > 0,60 bottom: scrollTop + clientHeight < scrollHeight - 1,61 left: scrollLeft > 0,62 right: scrollLeft + clientWidth < scrollWidth - 1,63 }));64 }, []);6566 React.useEffect(() => {67 if (typeof window === "undefined") return;6869 const element = viewportRef.current;70 if (!element) return;7172 const controller = new AbortController();73 const { signal } = controller;7475 const resizeObserver = new ResizeObserver(checkScrollability);76 resizeObserver.observe(element);7778 element.addEventListener("scroll", checkScrollability, { signal });79 window.addEventListener("resize", checkScrollability, { signal });8081 // Run an initial check whenever dependencies change (including pointer mode)82 checkScrollability();8384 return () => {85 controller.abort();86// … truncated
What it pulls in
npm packages
Files it writes
More from lina
All 10 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Command based on Lina's Base UI variantcommand-base | lina | Components | Free | 2 deps | |
| Command based on Lina's Radix UI variantcommand-radix | lina | Components | Free | 2 deps | |
| Horizontal Scroll Area Base Demohorizontal-scroll-demo-base | lina | Components | Free | no deps | |
| Horizontal Scroll Area Radix Demohorizontal-scroll-demo-radix | lina | Components | Free | no deps | |
| Radix Adaptive Scroll Arealina-radix | lina | Components | Free | 1 dep · 2 files | |
| Timezone Select Base UI Demotimezone-select-demo-base | lina | Components | Free | 1 dep | |
| Timezone Select Radix Demotimezone-select-demo-radix | lina | Components | Free | 1 dep | |
| Vertical Scroll Area Base Demovertical-scroll-demo-base | lina | Components | Free | no deps |
