---
name: ScrollView
menu: 'Components: UI'
route: /components/ui/scroll-view
---

# ScrollView

ScrollView makes long content scrollable.

import {
  Playground,
  Props,
} from 'docz'
import { Placeholder } from '../../../../docs/_components/Placeholder/Placeholder'
import { Button } from '../Button/Button'
import { Radio } from '../Radio/Radio'
import {
  TranslatedScrollView as ScrollView,
  ScrollView as ParsableScrollView,
} from './ScrollView'

## Basic Usage

To implement the ScrollView component, you need to import it first:

```js
import { ScrollView } from '@react-ui-org/react-ui';
```

And use it:

<Playground>
  <Placeholder height="200px">
    <ScrollView>
      <div>
        Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo
        ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis
        dis parturient montes, nascetur ridiculus mus. Donec quam felis,
        ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa
        quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget,
        arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.
        Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras
        dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend
        tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac,
        enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus.
        Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean
        imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper
        ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus
        eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing
        sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar,
        hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec
        vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit
        amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris
        sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget
        bibendum sodales, augue velit cursus nunc.Aenean massa. Cum sociis
        natoque penatibus et magnis dis parturient montes, nascetur ridiculus
        mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis,
        sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel,
        aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet
        a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium.
        Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean
        vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat
        vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis,
        feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet.
        Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue.
        Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus.
        Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper
        libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit
        vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante
        tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus.
        Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt.
        Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis
        magna. Sed consequat, leo eget bibendum sodales, augue velit cursus
        nunc.
      </div>
    </ScrollView>
  </Placeholder>
</Playground>

See [API](#api) for all available options.

## General Guidelines

- ScrollView takes up all **available horizontal space and expands vertically**
  according to the length of its content. Depending on your layout, you may need
  to restrict the height of its parent to activate scrolling.

- While arrow controls are optional in the vertical mode, you should always
  **enable arrows in the horizontal mode when scrollbar is disabled.** Because
  if you don't, users without horizontal-scrolling-enabled devices (like an
  old-school mouse) might not be able to access your content.

- For dynamic content such as chat window or console output, consider using the
  **auto-scroll feature**. This will ensure the newest content is always
  visible.

- ScrollView enables **scrolling on all screen sizes.** If you need to make an
  area in your app scrollable based on viewport size, please use custom CSS
  with media queries instead.

## Arrows

You can suppress the system scrollbar and display arrow controls instead.

<Playground>
  <Placeholder height="200px">
    <ScrollView arrows scrollbar={false}>
      <div>
        Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo
        ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis
        dis parturient montes, nascetur ridiculus mus. Donec quam felis,
        ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa
        quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget,
        arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.
        Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras
        dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend
        tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac,
        enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus.
        Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean
        imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper
        ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus
        eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing
        sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar,
        hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec
        vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit
        amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris
        sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget
        bibendum sodales, augue velit cursus nunc.Aenean massa. Cum sociis
        natoque penatibus et magnis dis parturient montes, nascetur ridiculus
        mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis,
        sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel,
        aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet
        a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium.
        Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean
        vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat
        vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis,
        feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet.
        Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue.
        Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus.
        Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper
        libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit
        vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante
        tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus.
        Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt.
        Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis
        magna. Sed consequat, leo eget bibendum sodales, augue velit cursus
        nunc.
      </div>
    </ScrollView>
  </Placeholder>
</Playground>

## Horizontal Scrolling

The horizontal mode is useful when you have (or expect to have) a lot of
horizontal content and you need to make sure it remains accessible on all
viewport sizes.

<Playground>
  <ScrollView direction="horizontal">
    <Placeholder>
      <div style={{ whiteSpace: 'nowrap' }}>
        Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo
        ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis
        dis parturient montes, nascetur ridiculus mus. Donec quam felis,
        ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa
        quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget,
        arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.
      </div>
    </Placeholder>
  </ScrollView>
</Playground>

## Auto Scrolling

ScrollView can watch its content for changes and automatically scroll to the
end when the content has changed.

⚠️ The auto-scroll functionality requires all children to have the `key`
property defined because it detects changes of these keys.

<Playground>
  {() => {
    const generateRandomString = () => {
      const texts = [
        'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.',
        'Aenean commodo ligula eget dolor. Aenean massa.',
        'Aenean commodo ligula eget dolor. Aenean massa.',
        'Cum sociis natoque penatibus et magnis dis parturient montes.',
        'Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem.',
        'Nulla consequat massa quis enim. Donec pede justo, fringilla vel.',
        'In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.',
      ];
      let text = '';
      const repeatAmount = Math.floor(Math.random() * 9);
      for (let i = 0; i < (repeatAmount + 1); i += 1) {
        text += texts[Math.floor(Math.random() * Math.floor(texts.length - 1))];
      }
      return text;
    }
    const [autoScroll, setAutoScroll] = React.useState('always');
    const [direction, setDirection] = React.useState('vertical');
    const [scrollViewContent, setScrollViewContent] = React.useState(
      generateRandomString(),
    );
    return (
      <>
        <div className="mb-5">
          <Radio
            changeHandler={(e) => setDirection(e.target.value)}
            options={[
              {
                label: 'Vertical',
                value: 'vertical',
              },
              {
                label: 'Horizontal',
                value: 'horizontal',
              },
            ]}
            id="scroll-view-direction"
            label="Direction:"
            value={direction}
          />
          <Radio
            changeHandler={(e) => setAutoScroll(e.target.value)}
            options={[
              {
                label: 'Always',
                value: 'always',
              },
              {
                label: 'When end is detected',
                value: 'detectEnd',
              },
            ]}
            id="scroll-view-autoscroll"
            label="Autoscroll:"
            value={autoScroll}
          />
          <Button
            label="Add text"
            clickHandler={
              () => setScrollViewContent(
                `${scrollViewContent} ${generateRandomString()}`,
              )
            }
          />
        </div>
        <Placeholder height={direction === 'vertical' ? '200px' : 'auto'}>
          <ScrollView arrows autoScroll={autoScroll} direction={direction}>
            <div
              key={scrollViewContent.length}
              style={{
                whiteSpace: (direction === 'horizontal' ? 'nowrap' : 'normal'),
              }}
            >
              {scrollViewContent}
            </div>
          </ScrollView>
        </Placeholder>
      </>
    );
  }}
</Playground>

## Customization

It's possible to entirely customize the arrow controls, including the scroll
step, and the scrolling shadows.

### Custom Arrows and Shadow Color

You can pass any HTML element or even custom React component to be used as the
arrow control.

The color of arrows and scrolling shadows can be simply adjusted, too. While the
`arrowsColor` accepts
[color in any valid CSS format](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value),
the `shadowColor` is broken down to individual color channels so we can easily
derive the transparent version from the value without having to parse it.

Furthermore, you can change the scroll step if you need to scroll by smaller or
bigger portions.

<Playground>
  <ScrollView
    arrows
    arrowsColor="white"
    arrowsScrollStep={300}
    customNextArrow={(
      <span
        style={{
          fontSize: '1.5rem',
          fontWeight: 'bold',
          position: 'relative',
          textShadow: '0 0 0.4em black',
          top: '-0.05em',
        }}
      >
        →
      </span>
    )}
    customPrevArrow={(
      <span
        style={{
          fontSize: '1.5rem',
          fontWeight: 'bold',
          position: 'relative',
          textShadow: '0 0 0.4em black',
          top: '-0.05em',
        }}
      >
        ←
      </span>
    )}
    direction="horizontal"
    scrollbar={false}
    shadowColor={{
      alpha: 0.75,
      blue: 0,
      green: 0,
      red: 0,
    }}
    shadowSize="5rem"
  >
    <Placeholder>
      <div style={{ whiteSpace: 'nowrap' }}>
        Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo
        ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis
        dis parturient montes, nascetur ridiculus mus. Donec quam felis,
        ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa
        quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget,
        arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.
      </div>
    </Placeholder>
  </ScrollView>
</Playground>

### Custom Scrolling Shadows

Aside from setting a custom shadow color and size, you can entirely customize
the scrolling shadows with `background` or `box-shadow` CSS properties.

The following example demonstrates exactly the same custom scrolling shadows as
we use in the [Modal](/components/ui/modal#scrolling-long-content) component.

<Playground>
  <Placeholder height="200px">
    <ScrollView
      customStartShadowStyle={{
        background: 'radial-gradient('
          + 'farthest-side at center top, '
          + 'rgba(0, 0, 0, 0.15) 0%, '
          + 'rgba(0, 0, 0, 0.05) 60%, '
          + 'rgba(0, 0, 0, 0.02) 85%, '
          + 'rgba(0, 0, 0, 0) 100%'
        + ')',
      }}
      customEndShadowStyle={{
        background: 'radial-gradient('
          + 'farthest-side at center bottom, '
          + 'rgba(0, 0, 0, 0.15) 0%, '
          + 'rgba(0, 0, 0, 0.05) 60%, '
          + 'rgba(0, 0, 0, 0.02) 85%, '
          + 'rgba(0, 0, 0, 0) 100%'
        + ')',
      }}
      shadowSize="40px"
    >
      <div>
        Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo
        ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis
        dis parturient montes, nascetur ridiculus mus. Donec quam felis,
        ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa
        quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget,
        arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.
        Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras
        dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend
        tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac,
        enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus.
        Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean
        imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper
        ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus
        eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing
        sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar,
        hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec
        vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit
        amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris
        sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget
        bibendum sodales, augue velit cursus nunc.Aenean massa. Cum sociis
        natoque penatibus et magnis dis parturient montes, nascetur ridiculus
        mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis,
        sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel,
        aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet
        a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium.
        Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean
        vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat
        vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis,
        feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet.
        Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue.
        Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus.
        Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper
        libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit
        vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante
        tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus.
        Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt.
        Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis
        magna. Sed consequat, leo eget bibendum sodales, augue velit cursus
        nunc.
      </div>
    </ScrollView>
  </Placeholder>
</Playground>

## API

<Props of={ParsableScrollView} />

---

Next: [SelectField →](/components/ui/select-field)
