Scroll area wrappers with themed scrollbar
import { ScrollArea, ScrollAreaViewport, ScrollBar } from '@/components/ui/scroll-area'
...import { ScrollArea, ScrollAreaViewport, ScrollBar } from '@/components/ui/scroll-area'
const tags = Array.from({ length: 50 }, (_, index) => `v1.2.0-beta.${50 - index}`)
export default function ScrollAreaDemoExample() {
return (
<ScrollArea class="h-72 w-48">
<ScrollAreaViewport>
<div class="p-4"><h4 class="mb-4 text-sm font-medium">Tags</h4>{tags.map(tag => <div class="border-b py-2 text-sm">{tag}</div>)}</div>
</ScrollAreaViewport>
<ScrollBar />
</ScrollArea>
)
}
Installation
npx @fictjs/shadcn@latest add scroll-areaInstall the runtime dependencies:
npm install @fictjs/radix-uiCopy the Fict shadcn component into your project.
Source
components/ui/scroll-area.tsx
src/components/ui/scroll-area.tsx
import { ScrollArea as ScrollAreaPrimitive } from '@fictjs/radix-ui'
import { cn } from '@/lib/cn'
type GenericProps = {
class?: string
children?: unknown
[key: string]: unknown
}
export function ScrollArea(props: GenericProps) {
const { class: className, ...rest } = props
return <ScrollAreaPrimitive.Root class={cn('relative overflow-hidden rounded-md border', className)} {...rest} />
}
export function ScrollBar(props: GenericProps) {
const { class: className, orientation = 'vertical', ...rest } = props
return (
<ScrollAreaPrimitive.Scrollbar
orientation={orientation}
class={cn(
'flex select-none touch-none p-0.5 transition-colors',
orientation === 'vertical' ? 'h-full w-2.5 border-l border-l-transparent' : 'h-2.5 w-full border-t border-t-transparent',
className,
)}
{...rest}
>
<ScrollAreaPrimitive.Thumb class='relative flex-1 rounded-full bg-border' />
</ScrollAreaPrimitive.Scrollbar>
)
}
export function ScrollAreaViewport(props: GenericProps) {
const { class: className, ...rest } = props
return <ScrollAreaPrimitive.Viewport class={cn('h-full w-full rounded-[inherit]', className)} {...rest} />
}
Usage
Examples
Horizontal Demo
import { ScrollArea, ScrollAreaViewport, ScrollBar } from '@/components/ui/scroll-area'
...import { ScrollArea, ScrollAreaViewport, ScrollBar } from '@/components/ui/scroll-area'
const works = [
{ artist: 'Ornella Binni', art: 'https://images.unsplash.com/photo-1465869185982-5a1a7522cbcb?auto=format&fit=crop&w=300&q=80' },
{ artist: 'Tom Byrom', art: 'https://images.unsplash.com/photo-1548516173-3cabfa4607e9?auto=format&fit=crop&w=300&q=80' },
{ artist: 'Vladimir Malyavko', art: 'https://images.unsplash.com/photo-1494337480532-3725c85fd2ab?auto=format&fit=crop&w=300&q=80' },
]
export default function ScrollAreaHorizontalDemoExample() {
return (
<ScrollArea class="w-96 whitespace-nowrap">
<ScrollAreaViewport>
<div class="flex w-max gap-4 p-4">{works.map(work => <figure class="shrink-0"><img class="aspect-[3/4] w-[300px] rounded-md object-cover" src={work.art} alt={`Photo by ${work.artist}`} /><figcaption class="pt-2 text-sm">Photo by <strong>{work.artist}</strong></figcaption></figure>)}</div>
</ScrollAreaViewport>
<ScrollBar orientation="horizontal" />
</ScrollArea>
)
}
Rtl
import { ScrollArea, ScrollAreaViewport, ScrollBar } from '@/components/ui/scroll-area'
...import { ScrollArea, ScrollAreaViewport, ScrollBar } from '@/components/ui/scroll-area'
const translations = {
ar: { dir: 'rtl', tags: 'العلامات' },
he: { dir: 'rtl', tags: 'תגיות' },
en: { dir: 'ltr', tags: 'Tags' },
} as const
const tags = Array.from({ length: 50 }, (_, index) => `v1.2.0-beta.${50 - index}`)
export default function ScrollAreaRtlExample() {
let language = $state<keyof typeof translations>('ar')
const text = () => translations[language]
return (
<div class="grid gap-4">
<select value={language} onChange={event => { language = event.currentTarget.value as keyof typeof translations }}>
<option value="ar">Arabic (العربية)</option><option value="he">Hebrew (עברית)</option><option value="en">English</option>
</select>
<ScrollArea dir={text().dir} class="h-72 w-48"><ScrollAreaViewport><div class="p-4"><h4 class="mb-4 text-sm font-medium">{text().tags}</h4>{tags.map(tag => <div class="border-b py-2 text-sm">{tag}</div>)}</div></ScrollAreaViewport><ScrollBar /></ScrollArea>
</div>
)
}