Skip to main content
Version: Next 🚧

Render props

When tokens and slots aren't enough, render props let you draw a part yourself. The component still handles touches, selection, scrolling and accessibility; you only render the visuals.

ComponentPropSignature
WheelPickerrenderItem({ item, index, selected, theme }) => ReactNode
WheelPickerrenderIndicator(theme) => ReactNode
Calendar / DatePickerrenderDay(state: DayState, theme) => ReactNode
Calendar / DatePickerrenderArrow(direction: 'prev' | 'next', disabled: boolean) => ReactNode
Calendar / DatePickerformatTitle(month: Date, locale?: string) => string
SelectPickerrenderTrigger({ open, selected, disabled }) => ReactNode
SelectPickerrenderChevron({ open, theme }) => ReactNode
SelectPicker / SelectListrenderOption({ option, selected, disabled, theme }) => ReactNode
SelectPicker / SelectListrenderGroupHeader(group: string, theme) => ReactNode
SelectPicker / SelectListrenderLoading(theme) => ReactNode
HorizontalListrenderItem({ item, selected, disabled, theme }) => ReactNode
*PickerField / PickerFieldrenderTrigger({ open, displayValue, disabled }) => ReactNode
*PickerField / PickerFieldrenderChevron({ open, theme }) => ReactNode
EmojiPickerrenderEmoji(emoji: string, data: Emoji, size: number) => ReactNode
MultiWheelPickerseparatorReactNode | (leftIndex) => ReactNode
BottomSheettitle, headerLeft, headerRight, footerReactNode

Every render prop receives the resolved theme, so custom parts stay correct in dark mode.

Calendar with availability prices​

Loading…
      <View
        style={{
          width: 44,
          height: 46,
          borderRadius: 12,
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: on ? theme.colors.primary : 'transparent',
        }}
      >
        <Text
          style={{
            fontWeight: '600',
            color: on
              ? theme.colors.onPrimary
              : s.disabled || s.outside
                ? theme.colors.textDisabled
                : theme.colors.text,
          }}
        >
          {s.date.getDate()}
        </Text>
        {!s.disabled && !s.outside && (
          <Text
            style={{
              fontSize: 9,
              color: on
                ? theme.colors.onPrimary
                : p < 100
                  ? '#16A34A'
                  : theme.colors.textSecondary,
            }}
          >
            ${p}
          </Text>
        )}
      </View>
    );
  }}
/>

Wheel with icons​

Loading…
<WheelPicker
  items={moods}
  value={mood}
  onChange={setMood}
  itemHeight={56}
  variant="flat"
  renderItem={({ item, selected, theme }) => (
    <View
      style={{
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'center',
        gap: 12,
      }}
    >
      <Text style={{ fontSize: selected ? 34 : 24 }}>
        {moods[item.value - 1].icon}
      </Text>
      <Text
        style={{
          fontSize: 18,
          fontWeight: selected ? '700' : '400',
          color: selected ? theme.colors.text : theme.colors.textSecondary,
        }}
      >
        {item.label}
      </Text>
    </View>
  )}
/>

Tips​

  • Keep render functions cheap. Wheels render a few rows, but they re-render as the selection moves.
  • Don't add your own Pressable around the whole of renderDay / renderOption / renderItem content. The cell is already pressable, and a nested pressable swallows the tap.
  • Read colours from the theme argument instead of hard-coding them, so dark mode keeps working.