Scroll

Scroll area with custom scrollbars for overflow.

import { Scroll } from 'ui-lab-components/scroll';
 
export function Example() {
  return (
    <Scroll maxHeight="300px">
      <div className="p-4 space-y-2">
        {Array.from({ length: 20 }).map((_, i) => (
          <div key={i} className="rounded-md bg-background-700 p-3">
            Item {i + 1}
          </div>
        ))}
      </div>
    </Scroll>
  );
}

scroll/01-scroll-basic-scroll

Vertically scrollable log output with fade mask to hint at overflow content.

Loading interactive preview
import { Scroll } from 'ui-lab-components/scroll';
 
export const metadata = {
  title: 'Log Viewer',
  description: 'Vertically scrollable log output with fade mask to hint at overflow content.'
};
 
const LOG_ENTRIES = [
  { level: "info", msg: "Server started on port 3000" },
  { level: "info", msg: "Connected to database" },
  { level: "warn", msg: "Slow query detected: users.findAll (342ms)" },
  { level: "error", msg: "Failed to send email: SMTP timeout" },
  { level: "info", msg: "Cache warmed: 1,204 keys loaded" },
  { level: "info", msg: "Background job 'sync-orders' started" },
  { level: "warn", msg: "Memory usage at 78%" },
  { level: "info", msg: "Background job 'sync-orders' completed" },
  { level: "error", msg: "Unhandled rejection: Cannot read property 'id' of undefined" },
  { level: "info", msg: "Health check passed" },
  { level: "warn", msg: "Rate limit reached for IP 192.168.1.42" },
  { level: "info", msg: "User #4821 logged in" },
  { level: "info", msg: "Deployment complete: v2.14.0" },
];
 
export default function Example() {
  return (
    <div style={{ width: 480, display: 'flex', flexDirection: 'column', gap: 4 }}>
      <span style={{ fontSize: 11, var(--color-muted)', textTransform: 'uppercase', letterSpacing: '0.08em' }}>
        Application Logs
      </span>
      <div style={{ border: '1px solid var(--color-border)', borderRadius: 6, background: 'var(--color-background-900)', overflow: 'hidden' }}>
        <Scroll maxHeight="200px" fade-y fadeDistance={8} fadeSize={5}>
          <div style={{ padding: '8px 0' }}>
            {LOG_ENTRIES.map((entry, i) => (
              <div key={i} style={{
                display: 'flex',
                gap: 10,
                padding: '3px 12px',
                fontSize: 12,
                fontFamily: 'var(--font-mono, monospace)',
                error'
                  ? 'var(--color-destructive)'
                  : entry.level === 'warn'
                    ? 'var(--color-warning, var(--color-muted))'
                    : 'var(--color-foreground)',
              }}>
                <span style={{ var(--color-muted)', minWidth: 36 }}>{entry.level}</span>
                <span>{entry.msg}</span>
              </div>
            ))}
          </div>
        </Scroll>
      </div>
    </div>
  );
}
 

scroll/02-scroll-settings-panel

Constrained-height settings list with a custom scrollbar shown on hover.

Loading interactive preview
import { Scroll } from 'ui-lab-components/scroll';
 
export const metadata = {
  title: 'Settings Panel',
  description: 'Constrained-height settings list with a custom scrollbar shown on hover.'
};
 
const SETTINGS_ITEMS = Array.from({ length: 18 }, (_, i) => ({
  label: `Option ${i + 1}`,
  description: `Configure behavior for setting ${i + 1}`,
}));
 
export default function Example() {
  return (
    <div style={{ width: 320, border: '1px solid var(--color-border)', borderRadius: 8, overflow: 'hidden', background: 'var(--color-background)' }}>
      <div style={{ padding: '12px 16px', borderBottom: '1px solid var(--color-border)', fontSize: 13, fontWeight: 500 }}>
        Preferences
      </div>
      <Scroll maxHeight="240px">
        <div style={{ padding: '8px 0' }}>
          {SETTINGS_ITEMS.map((item, i) => (
            <div key={i} style={{
              display: 'flex',
              justifyContent: 'space-between',
              alignItems: 'center',
              padding: '8px 16px',
              fontSize: 13,
              borderBottom: i < SETTINGS_ITEMS.length - 1 ? '1px solid var(--color-border)' : undefined,
            }}>
              <div>
                <div style={{ var(--color-foreground)' }}>{item.label}</div>
                <div style={{ fontSize: 11, var(--color-muted)', marginTop: 1 }}>{item.description}</div>
              </div>
            </div>
          ))}
        </div>
      </Scroll>
    </div>
  );
}
 

scroll/03-scroll-horizontal-tags

Horizontally scrollable row of filter tags that overflow their container.

Loading interactive preview
import { Scroll } from 'ui-lab-components/scroll';
 
export const metadata = {
  title: 'Horizontal Tag List',
  description: 'Horizontally scrollable row of filter tags that overflow their container.'
};
 
const TAGS = [
  "authentication", "payments", "webhooks", "analytics", "notifications",
  "billing", "user-management", "api-keys", "rate-limiting", "audit-logs",
  "exports", "integrations", "search", "permissions", "reports",
];
 
export default function Example() {
  return (
    <div style={{ width: 420, display: 'flex', flexDirection: 'column', gap: 6 }}>
      <span style={{ fontSize: 12, var(--color-muted)' }}>Filter by topic</span>
      <Scroll direction="horizontal" maxWidth="420px" hide={false} inline>
        <div style={{ display: 'flex', gap: 6, padding: '2px 0' }}>
          {TAGS.map((tag) => (
            <span key={tag} style={{
              whiteSpace: 'nowrap',
              padding: '3px 10px',
              border: '1px solid var(--color-border)',
              borderRadius: 4,
              fontSize: 12,
              var(--color-foreground)',
              cursor: 'default',
              background: 'var(--color-background-900)',
            }}>
              {tag}
            </span>
          ))}
        </div>
      </Scroll>
    </div>
  );
}
 
UI Lab