npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

react-native-strip-calendar

v0.1.6

Published

react native strip calendar

Readme

React Native Strip Calendar

화면 기록 2025-10-04 오후 2 52 31

A headless, customizable horizontal strip calendar component for React Native with virtualized scrolling and flexible styling support.

Features

  • 📅 Flexible Date Range: Define custom start and end dates
  • 🎨 Headless Design: Support for both StyleSheet and className (NativeWind) styling
  • Virtualized Scrolling: Smooth performance with large date ranges using @legendapp/list
  • 🌍 Internationalization: Built-in support for multiple locales via date-fns
  • 📱 React Native Compatible: Works with React Native and React Native Web
  • 🎯 Customizable Rendering: Custom day and header rendering functions
  • 📊 Marked Dates: Support for highlighting specific dates
  • 🔄 Navigation Controls: Previous/Next week navigation with boundary checks
  • 🧩 Compound Components: Modular design with Header, Week, Day, and Navigation components
  • 📏 Flexible Layout: Support for custom spacing with columnGap prop

Installation

npm install react-native-strip-calendar
# or
yarn add react-native-strip-calendar
# or
pnpm add react-native-strip-calendar

Peer Dependencies

This library requires the following peer dependencies:

npm install react react-native react-native-web

Basic Usage

Simple Calendar

import { StripCalendar } from 'react-native-strip-calendar';

export default function MyComponent() {
  return (
    <StripCalendar
      startDate={new Date('2025-01-01')}
      endDate={new Date('2025-12-31')}
      initialDate={new Date()}
      onDateChange={(date) => console.log('Selected date:', date)}
    >
      <StripCalendar.Header>
        {(dateString) => <Text>{dateString}</Text>}
      </StripCalendar.Header>
      <StripCalendar.Week />
      <StripCalendar.PreviousButton>
        {({ disabled }) => <Button disabled={disabled}>Previous</Button>}
      </StripCalendar.PreviousButton>
      <StripCalendar.NextButton>
        {({ disabled }) => <Button disabled={disabled}>Next</Button>}
      </StripCalendar.NextButton>
    </StripCalendar>
  );
}

With Custom Day Styling (using dayProps)

<StripCalendar
  startDate={new Date('2025-01-01')}
  endDate={new Date('2025-12-31')}
  initialDate={new Date()}
  selectedDate={selectedDate}
  onDateChange={setSelectedDate}
  markedDates={['2025-01-15', '2025-02-14', '2025-03-08']}
  containerHeight={120}
  itemWidth={48}
>
  <StripCalendar.Header>
    {(dateString) => (
      <Text style={styles.header}>
        {format(new Date(dateString), 'MMMM yyyy')}
      </Text>
    )}
  </StripCalendar.Header>
  <StripCalendar.Week
    columnGap={16}
    dayProps={{
      styles: {
        base: {
          container: {
            width: 48,
            height: 60,
            alignItems: 'center',
            justifyContent: 'center',
            borderRadius: 20,
            backgroundColor: '#f0f0f0',
            marginHorizontal: 1,
            marginVertical: 1,
          },
          dayName: {
            fontSize: 9,
            color: '#6b7280',
            fontWeight: '500',
            marginBottom: 2,
          },
          dayNumber: {
            fontSize: 16,
            color: '#374151',
            fontWeight: '600',
          },
        },
        today: {
          container: {
            backgroundColor: '#dbeafe',
            borderWidth: 2,
            borderColor: '#3b82f6',
          },
        },
        selected: {
          container: {
            backgroundColor: '#3b82f6',
          },
          dayNumber: {
            color: '#ffffff',
          },
        },
      },
    }}
  />
  <StripCalendar.PreviousButton>
    {({ disabled }) => (
      <Pressable
        style={[styles.button, disabled && styles.disabledButton]}
        disabled={disabled}
      >
        <Text>‹</Text>
      </Pressable>
    )}
  </StripCalendar.PreviousButton>
  <StripCalendar.NextButton>
    {({ disabled }) => (
      <Pressable
        style={[styles.button, disabled && styles.disabledButton]}
        disabled={disabled}
      >
        <Text>›</Text>
      </Pressable>
    )}
  </StripCalendar.NextButton>
</StripCalendar>

With Custom Day Renderer (using renderDay)

<StripCalendar
  startDate={new Date('2025-01-01')}
  endDate={new Date('2025-12-31')}
  initialDate={new Date()}
  selectedDate={selectedDate}
  onDateChange={setSelectedDate}
  markedDates={['2025-01-15', '2025-02-14', '2025-03-08']}
  containerHeight={120}
  itemWidth={48}
>
  <StripCalendar.Header>
    {(dateString) => (
      <Text style={styles.header}>
        {format(new Date(dateString), 'MMMM yyyy')}
      </Text>
    )}
  </StripCalendar.Header>
  <StripCalendar.Week
    columnGap={16}
    renderDay={({
      date,
      isSelected,
      isDisabled,
      isMarked,
      dayName,
      dayNumber,
      onPress,
    }) => (
      <Pressable
        style={[
          styles.customDay,
          isSelected && styles.selectedDay,
          isMarked && styles.markedDay,
          isDisabled && styles.disabledDay,
        ]}
        onPress={onPress}
        disabled={isDisabled}
      >
        <Text style={styles.dayName}>{dayName}</Text>
        <Text style={styles.dayNumber}>{dayNumber}</Text>
        {isMarked && <View style={styles.indicator} />}
      </Pressable>
    )}
  />
  <StripCalendar.PreviousButton>
    {({ disabled }) => (
      <Pressable
        style={[styles.button, disabled && styles.disabledButton]}
        disabled={disabled}
      >
        <Text>‹</Text>
      </Pressable>
    )}
  </StripCalendar.PreviousButton>
  <StripCalendar.NextButton>
    {({ disabled }) => (
      <Pressable
        style={[styles.button, disabled && styles.disabledButton]}
        disabled={disabled}
      >
        <Text>›</Text>
      </Pressable>
    )}
  </StripCalendar.NextButton>
</StripCalendar>

Props

StripCalendarProps

| Prop | Type | Default | Description | | ----------------- | ------------------------ | ------------ | ---------------------------------------------- | | initialDate | Date | new Date() | Initial date to display | | firstDay | Day | 1 | First day of the week (0 = Sunday, 1 = Monday) | | startDate | Date | undefined | Start date of the calendar range | | endDate | Date | undefined | End date of the calendar range | | minDate | Date | undefined | Minimum selectable date | | maxDate | Date | undefined | Maximum selectable date | | selectedDate | string | undefined | Currently selected date (YYYY-MM-DD format) | | onDateChange | (date: string) => void | undefined | Callback when date is selected | | containerHeight | number | 60 | Height of the calendar container | | itemWidth | number | 48 | Width of each day item | | markedDates | string[] | [] | Array of dates to mark (YYYY-MM-DD format) | | classNames | string | undefined | CSS class names for styling (NativeWind) | | styles | StyleProp<ViewStyle> | undefined | StyleSheet styles for styling | | locale | Locale | enUS | Locale for date formatting |

StripCalendar.Week Props

| Prop | Type | Description | | ----------------- | ---------------------- | ---------------------------------------- | | dayProps | DayProps | Props for the Day component | | renderDay | (props) => ReactNode | Custom day renderer function | | className | object | CSS class names for container and week | | style | object | StyleSheet styles for container and week | | columnGap | number | Gap between week columns (default: 12) | | containerHeight | number | Height of the week container |

Note: When renderDay is provided, dayProps are ignored. Use either dayProps for styling the default Day component or renderDay for completely custom day rendering.

DayProps

| Prop | Type | Description | | -------------- | ---------------------- | --------------------------------------------- | | date | CalendarDate | The date object to render | | classNames | DayStateClassNames | CSS class names for different day states | | styles | DayStateStyles | StyleSheet styles for different day states | | formatString | object | Custom format strings for day name and number | | renderDay | (props) => ReactNode | Custom day renderer function |

Compound Components

StripCalendar.Header

Renders the calendar header with the selected date.

<StripCalendar.Header>
  {(dateString) => (
    <Text style={styles.header}>
      {format(new Date(dateString), 'MMMM yyyy')}
    </Text>
  )}
</StripCalendar.Header>

StripCalendar.Week

Renders the week view with days. Supports two approaches:

Using dayProps (Default Day Component)

<StripCalendar.Week
  columnGap={16}
  className={{
    container: 'list-container',
    week: 'week-item',
  }}
  style={{
    container: { padding: 16 },
    week: { marginBottom: 8 },
  }}
  dayProps={{
    styles: {
      base: {
        container: styles.dayContainer,
        dayName: styles.dayName,
        dayNumber: styles.dayNumber,
      },
      today: {
        container: styles.todayContainer,
      },
      selected: {
        container: styles.selectedContainer,
      },
    },
  }}
/>

Using renderDay (Custom Day Component)

<StripCalendar.Week
  columnGap={16}
  className={{
    container: 'list-container',
    week: 'week-item',
  }}
  style={{
    container: { padding: 16 },
    week: { marginBottom: 8 },
  }}
  renderDay={({
    date,
    isSelected,
    isDisabled,
    isMarked,
    dayName,
    dayNumber,
    onPress,
  }) => (
    <Pressable
      style={[
        styles.customDay,
        isSelected && styles.selectedDay,
        isMarked && styles.markedDay,
        isDisabled && styles.disabledDay,
      ]}
      onPress={onPress}
      disabled={isDisabled}
    >
      <Text style={styles.dayName}>{dayName}</Text>
      <Text style={styles.dayNumber}>{dayNumber}</Text>
      {isMarked && <View style={styles.indicator} />}
    </Pressable>
  )}
/>

StripCalendar.Day

Renders a single day (useful for custom layouts).

<StripCalendar.Day
  date={dateObject}
  styles={customDayStyles}
  classNames={customDayClassNames}
/>

Styling

StyleSheet Approach

import { StyleSheet } from 'react-native';

<StripCalendar containerHeight={120} itemWidth={48}>
  <StripCalendar.Week
    columnGap={16}
    dayProps={{
      styles: {
        base: {
          container: styles.dayContainer,
          dayName: styles.dayName,
          dayNumber: styles.dayNumber,
        },
        today: {
          container: styles.todayContainer,
        },
        selected: {
          container: styles.selectedContainer,
        },
      },
    }}
  />
</StripCalendar>;

const styles = StyleSheet.create({
  dayContainer: {
    width: 48,
    height: 60,
    alignItems: 'center',
    justifyContent: 'center',
    borderRadius: 20,
    backgroundColor: '#f0f0f0',
    marginHorizontal: 1,
    marginVertical: 1,
  },
  dayName: {
    fontSize: 9,
    color: '#6b7280',
    fontWeight: '500',
    marginBottom: 2,
  },
  dayNumber: {
    fontSize: 16,
    color: '#374151',
    fontWeight: '600',
  },
  todayContainer: {
    backgroundColor: '#dbeafe',
    borderWidth: 2,
    borderColor: '#3b82f6',
  },
  selectedContainer: {
    backgroundColor: '#3b82f6',
  },
});

NativeWind/ClassName Approach

<StripCalendar containerHeight={120} itemWidth={48}>
  <StripCalendar.Week
    columnGap={16}
    dayProps={{
      classNames: {
        base: {
          container:
            'w-12 h-15 items-center justify-center rounded-xl bg-gray-100 mx-0.5 my-0.5',
          dayName: 'text-xs text-gray-500 font-medium mb-0.5',
          dayNumber: 'text-base text-gray-700 font-semibold',
        },
        today: {
          container: 'bg-blue-100 border-2 border-blue-500',
        },
        selected: {
          container: 'bg-blue-500',
          dayNumber: 'text-white',
        },
      },
    }}
  />
</StripCalendar>

Custom Rendering

Custom Day Renderer

<StripCalendar containerHeight={120} itemWidth={48}>
  <StripCalendar.Week
    columnGap={16}
    renderDay={({
      date,
      isSelected,
      isDisabled,
      isMarked,
      dayName,
      dayNumber,
      onPress,
    }) => (
      <Pressable
        style={[
          styles.customDay,
          isSelected && styles.selectedDay,
          isMarked && styles.markedDay,
          isDisabled && styles.disabledDay,
        ]}
        onPress={onPress}
        disabled={isDisabled}
      >
        <Text style={styles.dayName}>{dayName}</Text>
        <Text style={styles.dayNumber}>{dayNumber}</Text>
        {isMarked && <View style={styles.indicator} />}
      </Pressable>
    )}
  />
</StripCalendar>

Hooks

useHorizontalCalendar

A custom hook that provides calendar state and navigation logic:

import { useHorizontalCalendar } from 'react-native-strip-calendar';

const {
  weeksData,
  selectedDate,
  currentScrollIndex,
  initialScrollIndex,
  canGoNext,
  canGoPrevious,
  handleDateSelect,
  goToNextWeek,
  goToPreviousWeek,
  goToToday,
  scrollToWeek,
} = useHorizontalCalendar({
  initialDate: new Date(),
  firstDay: 1,
  startDate: new Date('2025-01-01'),
  endDate: new Date('2025-12-31'),
  onDateChange: (date) => console.log(date),
});

Internationalization

import { ko } from 'date-fns/locale';

<StripCalendar
  locale={ko}
  firstDay={1} // Monday
/>;

Example

See the example directory for a complete working example.

Development

# Install dependencies
pnpm install

# Build the library
pnpm build

# Run example
pnpm example:android
pnpm example:ios

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.