Skip to main content
Version: Next 🚧

HorizontalList

HorizontalList is a row of choices that scrolls sideways: a segmented control by default, or a row of chips. When the user taps the item at the edge and more items are hidden past it, the list scrolls a little so the next item comes into view.

import { HorizontalList } from '@elik56a/react-native-pickers';
Loading…
<HorizontalList items={views} value={view} onChange={setView} accessibilityLabel="Calendar view" />

Segmented controls​

A few items share the track's width. With more than fit, the track scrolls, and the thumb follows the selection along it.

Loading…
<View style={{ gap: 16 }}>
  <HorizontalList items={sorts} value={sort} onChange={setSort} accessibilityLabel="Sort by" />
  <HorizontalList items={ranges} value={range} onChange={setRange} accessibilityLabel="Chart range" />
</View>

Chips​

variant="chips" shows separate pills. With more items than fit, tap the last visible one: the list scrolls to show the next.

Loading…
<HorizontalList variant="chips" items={cuisines} value={cuisine} onChange={setCuisine} accessibilityLabel="Cuisine" />

Scroll arrows​

showArrows adds round ‹ › buttons that scroll the list about a page. They're off by default: swiping already scrolls on touch screens, so arrows help most with a mouse on the web, or a long row of chips.

By default (arrowPosition="outside") the arrows sit beside the list and show while its items overflow; the one that can't scroll further is dimmed, so the list keeps its width.

Loading…
<HorizontalList variant="chips" items={countries} value={country} onChange={setCountry} showArrows accessibilityLabel="Country" />

Over the edges​

arrowPosition="overlay" floats the arrows over the list's edges instead, each shown only while items are hidden past it, so the list keeps its full width.

Loading…
<HorizontalList
  variant="chips"
  items={topics}
  value={topic}
  onChange={setTopic}
  showArrows
  arrowPosition="overlay"
  accessibilityLabel="Topic"
/>

Custom arrows​

renderArrow(side, disabled) replaces the ‹ › glyph, and the arrow slot styles the button around it.

Loading…
<HorizontalList
  variant="chips"
  items={genres}
  value={genre}
  onChange={setGenre}
  showArrows
  renderArrow={(side, disabled) => (
    <Text style={{ fontSize: 16, fontWeight: '700', color: disabled ? theme.colors.textDisabled : theme.colors.primary }}>
      {side === 'left' ? '←' : '→'}
    </Text>
  )}
  styles={{ arrow: { backgroundColor: theme.colors.primaryMuted, borderWidth: 0, boxShadow: 'none' } }}
  accessibilityLabel="Genre"
/>

Icons​

Give an item an icon and choose its side with iconPosition: 'left' (the default), 'right', 'top' or 'bottom'. 'left' and 'right' follow the layout direction, so they swap in RTL. An icon can also be a function of { selected, disabled, color }, to color it like its label.

Loading…
<HorizontalList items={modes} value={mode} onChange={setMode} iconPosition="top" accessibilityLabel="Travel mode" />

Icons can be any view. Here each color filter has a swatch on its left:

Loading…
<HorizontalList variant="chips" items={colors} value={color} onChange={setColor} accessibilityLabel="Color" />

Disabled items​

A disabled item is dimmed and can't be chosen, like sizes that are sold out.

Loading…
<HorizontalList variant="chips" items={sizes} value={size} onChange={setSize} accessibilityLabel="Size" />

Any value type​

Values can be anything: numbers, ids, objects. HorizontalList<T> infers T from items, so onChange gets the typed value.

Loading…
<View style={{ gap: 12 }}>
  <HorizontalList items={tips} value={tip} onChange={setTip} accessibilityLabel="Tip" />
  <Text style={{ color: theme.colors.text, fontSize: 16 }}>Total: ${(bill * (1 + tip / 100)).toFixed(2)}</Text>
</View>

Object values are compared with Object.is. When they're recreated (say, refetched from a server), pass isEqual:

<HorizontalList items={plans} value={plan} onChange={setPlan} isEqual={(a, b) => a.id === b.id} />

Custom items​

renderItem draws each item's content, and the item slot resizes the pill around it. Here, a strip of the next three weeks:

Loading…
      <View style={{ alignItems: 'center', gap: 2 }}>
        <Text style={{ fontSize: 11, color: selected ? theme.colors.primary : theme.colors.textSecondary }}>
          {item.value === 0 ? 'Today' : date.toLocaleDateString(undefined, { weekday: 'short' })}
        </Text>
        <Text style={{ fontSize: 18, fontWeight: '700', color }}>{date.getDate()}</Text>
      </View>
    );
  }}
  accessibilityLabel="Day"
/>

Try the props​

Platform
variant
iconPosition
arrowPosition
<HorizontalList items={modes} value={mode} onChange={setMode} />

Behaviour​

  • Controlled: pass value and update it in onChange. Tapping the selected item calls onChange again.
  • In segmented, the thumb slides to the selected item; items share the track's width while they fit, and scroll when they don't.
  • Tapping an item whose neighbor is hidden scrolls that neighbor into view, plus a little of the one after it, so the user sees there's more.
  • With showArrows, the arrows need a frame around the list: style lays out that frame and styles.container styles the list itself.

Props​

PropTypeDefaultDescription
itemsReadonlyArray<HorizontalListItem<T>>required{ label, value, disabled?, icon? }. icon is a node, or a function of { selected, disabled, color }.
valueT | null—Selected value.
onChange(value: T, item) => void—Called on tap.
variant'segmented' | 'chips''segmented'Track with a sliding thumb, or separate pills.
iconPosition'left' | 'right' | 'top' | 'bottom''left'Where each icon sits around its label.
showArrowsbooleanfalseRound ‹ › buttons that scroll about a page, shown while the items overflow.
arrowPosition'outside' | 'overlay''outside'Beside the list, the one that can't scroll further dimmed; or over its edges, each shown while items hide past it.
renderArrow(side: 'left' | 'right', disabled: boolean) => ReactNode—Custom arrow content.
isEqual(a: T, b: T) => booleanObject.isValue equality.
renderItem(info: { item, selected, disabled, theme }) => ReactNode—Custom item content.
accessibilityLabelstring—Names the list for screen readers.
styleStyleProp<ViewStyle>—Container style.
stylesSlotStyles<HorizontalListSlot>—Slots below.
themeDeepPartial<PickerTheme>—Theme override.
design'ios' | 'material' | 'web'from PickersProviderThe look to follow, over the provider's: iOS, Material or web.
testIDstring—Test ID; items get {testID}-item-{index}.

Slots​

SlotElement
containerThe scroll view (the track in segmented)
contentThe row inside it
item / selectedItemEach item / the selected one
itemLabel / selectedItemLabelItem label
thumbThe sliding thumb (segmented)
arrow / arrowTextEach scroll arrow / its glyph (showArrows)

Accessibility​

The list is a radiogroup named by accessibilityLabel; items are radios with checked and disabled states. Scroll arrows are buttons labelled "Scroll left" and "Scroll right".