Scroll indicator, the shadow, provides an extra visual cue that content exists below or above the fold.
const loremIpsum =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temporincididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
render (
<Stack>
<Scroll height="100px" className="m-r-3" scrollIndicator>
<BodyText>With scroll indicator. {loremIpsum}</BodyText>
</Scroll>
<Scroll height="100px" className="m-r-3">
<BodyText>{loremIpsum}</BodyText>
</Scroll>
</Stack>
)
Size
Maximum width and height may be set explicitly via props, as in example above. Size also may be controlled by external container.
const loremIpsum =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temporincididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
render (
<Card padding="none" light className="of-hidden">
<Card.Section style={{ height: '100px' }}>
<Scroll scrollIndicator>
<div className="m-x-2 m-y-2">
<BodyText>
Height is controlled by container.
</BodyText>
<BodyText className="m-t-1">{loremIpsum}</BodyText>
<BodyText className="m-t-1">{loremIpsum}</BodyText>
</div>
</Scroll>
</Card.Section>
</Card>
);
Horizontal
If content goes further rigth side of the Scroll, it may reflect such behavior.
<State initial={{}}>
{([state, setState]) => {
const names =
['Ben Ho', 'Matt Felton', 'James Coyle', 'Sergey Ya', 'Ara Mah', 'Doctor Rex', 'Alex Star', 'Trent Walton', 'Crazy Horse', 'Greg High', 'John Puy', 'Elen Lupton', 'Karl Wisley', 'Pol Obrian',];
return (
<Card light className="of-hidden">
<Card.Section className="h3">Participants</Card.Section>
<Card.Section className="p-0">
<Scroll horizontal="scroll" scrollIndicator>
<div className="m-x-2 m-y-2 d-f">
{names.map((name, nameIndex) => (
<div className="m-r-2" key={`name${nameIndex}`}>
<Avatar
autoColor
name={name}
size="l"
/>
</div>
))}
</div>
</Scroll>
</Card.Section>
</Card>
);
}}
</State>
User is capable to scroll content even without visible scrollbar.
<State initial={{}}>
{([state, setState]) => {
const loremIpsum =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temporincididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
return (
<div className="m-t-8">
<Popover
direction="tr"
open
trigger={<Button>Popover</Button>}
padding={null}
>
<Scroll height="118px" scrollbar="hidden" scrollIndicator>
<div className="p-x-3 p-y-2">
<BodyText>{loremIpsum}</BodyText>
</div>
</Scroll>
</Popover>
</div>
);
}}
</State>
Use Cases
Scroll component intended to be used in:
- overlay components, like Modal, Drawer, Popover, Toast, Takeover, ActionMenu, etc., where scrollable behavior might be unexpected
- fixed-size components, like Card, Tab, Sidebar, where extra visual hint come in handy
- Select component in case of too long list of options, which makes scrollbar unusable
Examples
<State initial={{}}>
{([state, setState]) => {
const loremIpsum =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temporincididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
return (
<Modal
title="Modal Title"
closable
open
onClose={() => {}}
footer={
<ButtonGroup>
<Button>Cancel</Button>
<Button primary>Save</Button>
</ButtonGroup>
}
portal={false}
size={Modal.Sizes.S}
>
<div
style={{
margin: `-${tokens.spacing3} -${tokens.spacing4}`,
height: `calc(100% + ${tokens.spacing5})`,
}}
>
<Scroll scrollIndicator>
<div className="p-3">
<BodyText>{loremIpsum}</BodyText>
<BodyText className="m-t-2">{loremIpsum}</BodyText>
</div>
</Scroll>
</div>
</Modal>
);
}}
</State>
<State initial={{}}>
{([state, setState]) => {
const loremIpsum =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temporincididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
return (
<Drawer
open
header="Drawer"
onClose={() => {}}
portal={false}
footer={
<ButtonGroup>
<Button>Cancel</Button>
<Button primary>Save</Button>
</ButtonGroup>
}
>
<div
style={{
margin: `-${tokens.spacing3}`,
height: `calc(100% + ${tokens.spacing5})`,
}}
>
<Scroll scrollIndicator>
<div className="p-3">
<BodyText>{loremIpsum}</BodyText>
<BodyText className="m-t-2">{loremIpsum}</BodyText>
<BodyText className="m-t-2">{loremIpsum}</BodyText>
<BodyText className="m-t-2">{loremIpsum}</BodyText>
</div>
</Scroll>
</div>
</Drawer>
);
}}
</State>
<State initial={{}}>
{([state, setState]) => {
const loremIpsum =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod temporincididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
return (
<Takeover
backLabel="Previous Page"
title="Takeover Title"
footer={
<ButtonGroup>
<Button>Cancel</Button>
<Button primary>Save</Button>
</ButtonGroup>
}
footerAlign="right"
onClose={() => {}}
portal={false}
>
<Takeover.Section
style={{ padding: '0px', height: '100%' }}
>
<Scroll scrollIndicator>
<div className="p-3">
<BodyText>{loremIpsum}</BodyText>
<BodyText className="m-t-2">
{loremIpsum}
</BodyText>
<BodyText className="m-t-2">
{loremIpsum}
</BodyText>
<BodyText className="m-t-2">
{loremIpsum}
</BodyText>
</div>
</Scroll>
</Takeover.Section>
</Takeover>
);
}}
</State>
Importing
import { Scroll } from '@servicetitan/design-system';