Scrollbar The Scrollbar
component provides a consistent look and feel for scrollbars across multiple platforms and browsers.
Import copy import {
Scrollbar ,
} from '@trendmicro/react-styled-ui' ;
Usage The scrollbar is hidden by default. You can mouse over the scrollable content to show the scrollbar.
EDITABLE EXAMPLE
copy < Scrollbar
height = { 200 }
border = { 1 }
borderColor = " #424242 "
>
< Lorem count = { 10 } px = " 4x " py = " 3x " />
</ Scrollbar >
Scroll direction The examples below illustrate the different scroll directions. You can try to resize the scrollable content to see how the scrollbar changes.
Vertical scrolling To enable vertical scrolling, set the scrollbar height to a value less than the scrollable content height.
EDITABLE EXAMPLE
copy < Scrollbar
width = " 50% "
height = { 200 }
minHeight = { 100 }
maxHeight = { 300 }
border = { 1 }
borderColor = " #424242 "
overflow = " scroll "
resize = " vertical "
>
< Lorem count = { 10 } px = " 4x " py = " 3x " />
</ Scrollbar >
Horizontal scrolling To enable horizontal scrolling, set the scrollbar width to a value less than the scrollable content width.
EDITABLE EXAMPLE
copy < Scrollbar
width = " 50% "
height = " auto "
minWidth = " 10% "
maxWidth = " 100% "
border = { 1 }
borderColor = " #424242 "
overflow = " scroll "
resize = " horizontal "
>
< Lorem count = { 6 } px = " 4x " py = " 3x " whiteSpace = " nowrap " />
</ Scrollbar >
Bidirectional scrolling
EDITABLE EXAMPLE
copy < Scrollbar
width = " 50% "
height = { 200 }
border = { 1 }
borderColor = " #424242 "
overflow = " scroll "
resize = " both "
>
< Lorem count = { 10 } px = " 4x " py = " 3x " whiteSpace = " nowrap " />
</ Scrollbar >
Overflow control Use the overflow
prop to set the overflow of the content. You can set the value to auto
, scroll
, or hidden
.
auto
: The scrollbar will be shown if the content overflows and mouse is hovering over the content.scroll
: The scrollbar is always visible if the content overflows.hidden
: The scrollbar is never shown.Note: overflowX
and overflowY
are also available if you need to set the overflow on both X and Y axis.
EDITABLE EXAMPLE
copy < Stack direction = " row " spacing = " 4x " >
< Box flex = " 1 " >
< Text size = " xl " marginBottom = " 2x " >
overflow="auto"
</ Text >
< Scrollbar
height = { 200 }
border = { 1 }
borderColor = " #424242 "
overflow = " auto "
>
< Lorem count = { 10 } px = " 4x " py = " 3x " whiteSpace = " nowrap " />
</ Scrollbar >
</ Box >
< Box flex = " 1 " >
< Text size = " xl " marginBottom = " 2x " >
overflow="scroll"
</ Text >
< Scrollbar
height = { 200 }
border = { 1 }
borderColor = " #424242 "
overflow = " scroll "
>
< Lorem count = { 10 } px = " 4x " py = " 3x " whiteSpace = " nowrap " />
</ Scrollbar >
</ Box >
< Box flex = " 1 " >
< Text size = " xl " marginBottom = " 2x " >
overflow="hidden"
</ Text >
< Scrollbar
height = { 200 }
border = { 1 }
borderColor = " #424242 "
overflow = " hidden "
>
< Lorem count = { 10 } px = " 4x " py = " 3x " whiteSpace = " nowrap " />
</ Scrollbar >
</ Box >
</ Stack >
Scrollbar thumb Use the minThumbWidth
and minThumbHeight
props to set the minimum size of the thumb (in pixels).
EDITABLE EXAMPLE
copy < Stack direction = " row " spacing = " 4x " >
< Box flex = " 1 " >
< Text size = " xl " marginBottom = " 2x " >
minThumbHeight=50
</ Text >
< Scrollbar
height = { 200 }
border = { 1 }
borderColor = " #424242 "
minThumbHeight = { 50 }
overflow = " scroll "
>
< Lorem count = { 10 } px = " 4x " py = " 3x " />
</ Scrollbar >
</ Box >
< Box flex = " 1 " >
< Text size = " xl " marginBottom = " 2x " >
minThumbHeight=100
</ Text >
< Scrollbar
height = { 200 }
border = { 1 }
borderColor = " #424242 "
minThumbHeight = { 100 }
overflow = " scroll "
>
< Lorem count = { 10 } px = " 4x " py = " 3x " />
</ Scrollbar >
</ Box >
</ Stack >
Scroll indicator The scroll indicator can visually indicate the current scroll position of the scrollable element, so that the user knows whether it can be scrolled further.
EDITABLE EXAMPLE
copy const ShadowScrollbar = ( props ) => {
const topIndicatorRef = React . useRef ( null ) ;
const bottomIndicatorRef = React . useRef ( null ) ;
const handleUpdate = ( { values } ) => {
const { scrollTop , scrollHeight , clientHeight } = values ;
const topIndicatorOpacity = 1 / 20 * Math . min ( scrollTop , 20 ) ;
const bottomScrollTop = scrollHeight - clientHeight ;
const bottomIndicatorOpacity = 1 / 20 * ( bottomScrollTop - Math . max ( scrollTop , bottomScrollTop - 20 ) ) ;
topIndicatorRef . current . style . opacity = topIndicatorOpacity ;
bottomIndicatorRef . current . style . opacity = bottomIndicatorOpacity ;
} ;
return (
< Box position = " relative " >
< Scrollbar
onUpdate = { handleUpdate }
{ ... props }
/>
< Box
ref = { topIndicatorRef }
position = " absolute "
top = " 0 "
left = " 0 "
right = " 0 "
height = " 24px "
background = " linear-gradient(to bottom, rgba(33, 33, 33, 1) 0%, rgba(255, 255, 255, 0) 100%) "
/>
< Box
ref = { bottomIndicatorRef }
position = " absolute "
bottom = " 0 "
left = " 0 "
right = " 0 "
height = " 24px "
background = " linear-gradient(to top, rgba(33, 33, 33, 1) 0%, rgba(255, 255, 255, 0) 100%) "
/>
</ Box >
) ;
}
render (
< ShadowScrollbar
height = { 300 }
border = { 1 }
borderColor = " #424242 "
>
< Lorem count = { 10 } px = " 4x " py = " 3x " />
</ ShadowScrollbar >
) ;
Scrollable menu
EDITABLE EXAMPLE
copy < Menu width = " 160px " >
< MenuButton width = " 100% " > Select an option </ MenuButton >
< MenuList width = " 100% " height = { 200 } >
< Scrollbar >
< MenuItem > List item 1 </ MenuItem >
< MenuItem > List item 2 </ MenuItem >
< MenuItem > List item 3 </ MenuItem >
< MenuItem > List item 4 </ MenuItem >
< MenuItem > List item 5 </ MenuItem >
< MenuItem > List item 6 </ MenuItem >
< MenuItem > List item 7 </ MenuItem >
< MenuItem > List item 8 </ MenuItem >
< MenuItem > List item 9 </ MenuItem >
< MenuItem > List item 10 </ MenuItem >
< MenuItem > List item 11 </ MenuItem >
< MenuItem > List item 12 </ MenuItem >
</ Scrollbar >
</ MenuList >
</ Menu >
Scrollable table
EDITABLE EXAMPLE
copy const CustomScrollbar = ( {
children ,
... rest
} ) => {
const [ colorMode ] = useColorMode ( ) ;
const backgroundColor = {
dark : 'gray:70' ,
light : 'gray:30' ,
} [ colorMode ] ;
return (
< Scrollbar
{ ... rest }
>
{ ( {
ScrollView ,
HorizontalTrack ,
VerticalTrack ,
HorizontalThumb ,
VerticalThumb ,
getScrollViewProps ,
getHorizontalTrackProps ,
getVerticalTrackProps ,
getHorizontalThumbProps ,
getVerticalThumbProps ,
} ) => (
< >
< ScrollView { ... getScrollViewProps ( ) } >
{ children }
</ ScrollView >
< HorizontalTrack
{ ... getHorizontalTrackProps ( ) }
backgroundColor = { backgroundColor }
>
< HorizontalThumb { ... getHorizontalThumbProps ( ) } />
</ HorizontalTrack >
< VerticalTrack
{ ... getVerticalTrackProps ( ) }
backgroundColor = { backgroundColor }
>
< VerticalThumb { ... getVerticalThumbProps ( ) } />
</ VerticalTrack >
</ >
) }
</ Scrollbar >
) ;
} ;
function ScrollableTable ( ) {
const tableHeaderRef = React . createRef ( ) ;
const [ isHorizontalScrollbarVisible , setHorizontalScrollbarVisible ] = React . useState ( false ) ;
const [ isVerticalScrollbarVisible , setVerticalScrollbarVisible ] = React . useState ( false ) ;
const columns = React . useMemo ( ( ) => [
{
Header : 'Event Type' ,
accessor : 'eventType' ,
} ,
{
Header : 'Affected Devices' ,
accessor : 'affectedDevices' ,
customProps : {
textAlign : 'right' ,
} ,
} ,
{
Header : 'Detections' ,
accessor : 'detections' ,
customProps : {
textAlign : 'right' ,
} ,
} ,
] , [ ] ) ;
const data = React . useMemo ( ( ) => [
{ id : 1 , eventType : 'Virus/Malware' , affectedDevices : 20 , detections : 634 } ,
{ id : 2 , eventType : 'Spyware/Grayware' , affectedDevices : 20 , detections : 634 } ,
{ id : 3 , eventType : 'URL Filtering' , affectedDevices : 15 , detections : 598 } ,
{ id : 4 , eventType : 'Web Reputation' , affectedDevices : 15 , detections : 598 } ,
{ id : 5 , eventType : 'Network Virus' , affectedDevices : 15 , detections : 497 } ,
{ id : 6 , eventType : 'Application Control' , affectedDevices : 0 , detections : 0 }
] , [ ] ) ;
const onScroll = ( e ) => {
const scrollLeft = e . target . scrollLeft ;
if ( tableHeaderRef . current && tableHeaderRef . current . scrollLeft !== scrollLeft ) {
tableHeaderRef . current . scrollLeft = scrollLeft ;
}
} ;
const onUpdate = ( props ) => {
const { scrollWidth , clientWidth , scrollHeight , clientHeight } = props ;
const _isHorizontalScrollbarVisible = ( scrollWidth > clientWidth ) ;
const _isVerticalScrollbarVisible = ( scrollHeight > clientHeight ) ;
if ( _isHorizontalScrollbarVisible !== isHorizontalScrollbarVisible ) {
setHorizontalScrollbarVisible ( _isHorizontalScrollbarVisible ) ;
}
if ( _isVerticalScrollbarVisible !== isVerticalScrollbarVisible ) {
setVerticalScrollbarVisible ( _isVerticalScrollbarVisible ) ;
}
} ;
const {
getTableProps ,
getTableBodyProps ,
headerGroups ,
rows ,
prepareRow
} = useTable (
{
columns ,
data ,
} ,
useBlockLayout ,
) ;
return (
< Table
variant = " outline "
width = { 400 }
height = { 200 }
{ ... getTableProps ( ) }
>
< TableHeader ref = { tableHeaderRef } >
{ headerGroups . map ( headerGroup => {
const { style , ... props } = headerGroup . getHeaderGroupProps ( ) ;
let headerWidth = style . width ;
if ( isVerticalScrollbarVisible ) {
headerWidth = ` calc( ${ style . width } + 8px) ` ;
}
return (
< TableHeaderRow style = { { ... style , width : headerWidth } } { ... props } >
{ headerGroup . headers . map ( ( column , index ) => (
< TableHeaderCell
key = { column . accessor }
{ ... column . getHeaderProps ( ) }
{ ... column . customProps }
{...(isVerticalScrollbarVisible && index = = = headerGroup.headers.length - 1) && {
borderRight: 0,
}}
>
{ column . render ( 'Header' ) }
</ TableHeaderCell >
) ) }
{ isVerticalScrollbarVisible && (
< TableHeaderCell width = " 2x " padding = { 0 } borderLeft = { 0 } />
) }
</ TableHeaderRow >
) ;
} ) }
</ TableHeader >
< CustomScrollbar
onScroll = { onScroll }
onUpdate = { onUpdate }
>
< TableBody { ... getTableBodyProps ( ) } >
{ rows . map ( ( row , index ) => {
prepareRow ( row ) ;
return (
< TableRow
{ ... row . getRowProps ( ) }
key = { index }
_hover = { {
bg : 'rgba(255, 255, 255, 0.12)'
} }
>
{ row . cells . map ( cell => {
return (
< TableCell
key = { cell . id }
{ ... cell . getCellProps ( ) }
{ ... cell . column . customProps }
>
{ cell . render ( 'Cell' ) }
</ TableCell >
) ;
} ) }
</ TableRow >
) ;
} ) }
</ TableBody >
</ CustomScrollbar >
</ Table >
) ;
}
render ( < ScrollableTable /> ) ;
Props Name Type Default Description children ReactNode | function The content of the scrollbar. width number | string '100%' The width of the scrollbar. If set to 'auto', you can constrain the width using the minWidth
and maxWidth
props. height number | string '100%' The height of the scrollbar. If set to 'auto', you can constrain the height using the minHeight
and maxHeight
props. minWidth number | string The minimum width of the scrollbar. maxWidth number | string The maximum width of the scrollbar. minHeight number | string The minimum height of the scrollbar. maxHeight number | string The maximum height of the scrollbar. minThumbWidth number 32 The minimum width of the thumb in pixels. minThumbHeight number 32 The minimum height of the thumb in pixels. onScroll function A callback function that is called when the scrollbar is scrolled. onUpdate function A callback function that is called when the scrollbar is updated. overflow string 'auto' The overflow of the scrollable content. One of: 'auto', 'scroll', 'hidden'. overflowX string The horizontal overflow of the scrollable content. One of: 'auto', 'scroll', 'hidden'. overflowY string The vertical overflow of the scrollable content. One of: 'auto', 'scroll', 'hidden'.
Further Reading