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-availability-grid

v0.1.2

Published

React component for selecting time availability across multiple days. Perfect for meeting schedulers and booking systems.

Downloads

289

Readme

react-availability-grid

A React component for selecting time availability across multiple days. Perfect for building meeting schedulers, booking systems, and "when are you free?" tools.

Features

  • Drag to select - Click and drag to quickly select multiple time slots
  • Lightweight - Small bundle size (13KB gzipped)
  • Fully accessible - ARIA support and complete keyboard navigation
  • Easy to customize - Style with CSS variables or custom classes
  • TypeScript ready - Full type definitions included
  • Flexible configuration - Set intervals, date ranges, and disabled times
  • Modern React - Built with hooks, works with React 16.8+

Installation

npm install react-availability-grid dayjs react react-dom

or

yarn add react-availability-grid dayjs react react-dom

Quick Start

import { useState } from 'react';
import { TimeGrid } from 'react-availability-grid';
import type { Dayjs } from 'react-availability-grid';
import 'react-availability-grid/styles.css';
import dayjs from 'dayjs';

function App() {
  const [selection, setSelection] = useState<Dayjs[]>([]);

  return (
    <TimeGrid
      selection={selection}
      setSelection={setSelection}
      startDate={dayjs()}
      endDate={dayjs().add(2, 'weeks')}
      earliestStart={dayjs().hour(9).minute(0)}
      latestEnd={dayjs().hour(17).minute(0)}
    />
  );
}

Props API

Required Props

| Prop | Type | Description | |------|------|-------------| | selection | Dayjs[] | Array of selected time slots | | setSelection | (selection: Dayjs[] \| ((prev: Dayjs[]) => Dayjs[])) => void | Function to update selection | | startDate | Dayjs | First day to display in the grid | | endDate | Dayjs | Last day to display in the grid | | earliestStart | Dayjs | Earliest time of day to show (e.g., 9:00 AM) | | latestEnd | Dayjs | Latest time of day to show (e.g., 5:00 PM) |

Optional Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | intervalSize | number | 60 | Size of each time slot in minutes | | allowedTimes | Dayjs[] | undefined | Whitelist of allowed time slots. If omitted, all future times are allowed. Must be memoized to avoid re-renders. | | onSelectionChange | (selection: Dayjs[]) => void | undefined | Callback fired when selection changes | | className | string | undefined | Additional CSS class for the grid container | | style | React.CSSProperties | undefined | Inline styles for the grid container |

Usage Examples

Basic Weekly Schedule

import { TimeGrid } from 'react-availability-grid';
import dayjs from 'dayjs';

function WeeklySchedule() {
  const [availability, setAvailability] = useState<Dayjs[]>([]);

  return (
    <TimeGrid
      selection={availability}
      setSelection={setAvailability}
      startDate={dayjs().startOf('week')}
      endDate={dayjs().endOf('week')}
      earliestStart={dayjs().hour(9).minute(0)}
      latestEnd={dayjs().hour(17).minute(0)}
      intervalSize={60}
    />
  );
}

30-Minute Intervals

<TimeGrid
  selection={selection}
  setSelection={setSelection}
  startDate={dayjs()}
  endDate={dayjs().add(7, 'days')}
  earliestStart={dayjs().hour(8).minute(0)}
  latestEnd={dayjs().hour(20).minute(0)}
  intervalSize={30}
/>

With Selection Callback

<TimeGrid
  selection={selection}
  setSelection={setSelection}
  startDate={dayjs()}
  endDate={dayjs().add(1, 'week')}
  earliestStart={dayjs().hour(9).minute(0)}
  latestEnd={dayjs().hour(17).minute(0)}
  onSelectionChange={(newSelection) => {
    console.log(`Selected ${newSelection.length} time slots`);
    // Send to analytics, update UI, etc.
  }}
/>

Custom Styling

<TimeGrid
  selection={selection}
  setSelection={setSelection}
  startDate={dayjs()}
  endDate={dayjs().add(1, 'week')}
  earliestStart={dayjs().hour(9).minute(0)}
  latestEnd={dayjs().hour(17).minute(0)}
  className="my-custom-grid"
  style={{ maxWidth: '900px', margin: '0 auto' }}
/>

Restrict Available Times

import { useMemo } from 'react';

function MyScheduler() {
  const [selection, setSelection] = useState<Dayjs[]>([]);

  // IMPORTANT: Memoize allowedTimes to prevent unnecessary re-renders
  const businessHours = useMemo(() => {
    const times: Dayjs[] = [];
    let current = dayjs().startOf('week').add(1, 'day'); // Monday

    while (current.isBefore(dayjs().endOf('week'))) {
      if (current.day() !== 0 && current.day() !== 6) { // Skip weekends
        for (let hour = 9; hour < 17; hour++) {
          times.push(current.hour(hour).minute(0).second(0).millisecond(0));
        }
      }
      current = current.add(1, 'day');
    }

    return times;
  }, []); // Recalculate if date range changes

  return (
    <TimeGrid
      selection={selection}
      setSelection={setSelection}
      startDate={dayjs().startOf('week')}
      endDate={dayjs().endOf('week')}
      earliestStart={dayjs().hour(9).minute(0)}
      latestEnd={dayjs().hour(17).minute(0)}
      allowedTimes={businessHours}
    />
  );
}

Styling & Theming

The component uses CSS variables for easy theming. Import the CSS file and override variables as needed:

:root {
  --timegrid-cell-bg: #f0f0f0;
  --timegrid-cell-selected-bg: #346dee5e;
  --timegrid-cell-disabled-color: #c5c5c5ad;
  --timegrid-cell-border-color: #fff;
  --timegrid-cell-text-color: #2f2f2fad;
  --timegrid-day-bg: #f0f0f0;
  --timegrid-day-number-color: #156ff7;
  --timegrid-weekend-bg: #dedee2;
  --timegrid-border-radius: 4px;
  --timegrid-cell-width: 50px;
  --timegrid-cell-height: 25px;
  --timegrid-day-height: 60px;
}

Custom Theme Example

/* Dark theme */
:root {
  --timegrid-cell-bg: #2a2a2a;
  --timegrid-cell-selected-bg: #4a9eff;
  --timegrid-cell-border-color: #1a1a1a;
  --timegrid-cell-text-color: #e0e0e0;
  --timegrid-day-bg: #333;
  --timegrid-weekend-bg: #252525;
}

Accessibility

TimeGrid is built with accessibility in mind:

  • ARIA Roles: Grid uses proper role="grid", role="row", role="gridcell", and role="columnheader" attributes
  • Screen Reader Support: All cells have descriptive aria-label attributes announcing the day, time, and selection state
  • Keyboard Navigation:
    • Tab: Focus cells in sequential order
    • Arrow Keys: Navigate between cells (Up/Down for hours, Left/Right for days)
    • Space/Enter: Toggle selection of focused cell
  • Focus Management: Visual focus indicators and proper tabIndex management

Browser Support

Works in all modern browsers that support:

  • ES6+
  • React 16.8+ (Hooks)
  • CSS Grid
  • CSS Custom Properties

Tested in:

  • Chrome/Edge 90+
  • Firefox 88+
  • Safari 14+

TypeScript

Full TypeScript support included. Import types as needed:

import type { TimeGridProps, Dayjs } from 'react-availability-grid';

const props: TimeGridProps = {
  selection: [],
  setSelection: () => {},
  startDate: dayjs(),
  endDate: dayjs().add(1, 'week'),
  earliestStart: dayjs().hour(9).minute(0),
  latestEnd: dayjs().hour(17).minute(0),
};

Development

# Install dependencies
npm install

# Start development server
npm start

# Build library
npm run build:lib

# Run tests
npm test

License

MIT