> ## Documentation Index
> Fetch the complete documentation index at: https://super-calendar.afonsojramos.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Time grid

> The week, day, 3-day, and custom hour-by-hour views.

<Note>
  Examples use the React Native `Calendar`; most props are shared with the dom renderer, and the
  [dom vs native comparison](/reference/renderers) lists what differs per renderer.
</Note>

`mode="week"`, `day`, `3days`, and `custom` all render the time grid: one
column per day, hours down the side, events as positioned boxes, and an all-day
lane on top. On React Native the day header and the all-day lane page with the
columns while the hour column stays fixed on the left, so the whole grid moves as
one when you swipe. `week` pages by the calendar week (set `weekStartsOn`: 0 = Sunday,
1 = Monday, and so on); `day` and `3days` page by their column count; [`custom`](/guides/views#custom-day-counts) renders any slice you
choose.

```tsx theme={null}
<Calendar
  mode="week"
  date={date}
  events={events}
  scrollOffsetMinutes={8 * 60} // open scrolled to 8am
  onChangeDate={setDate}
/>
```

`scrollOffsetMinutes` is applied on mount and again whenever its value changes,
at the current zoom. Keep it stable rather than deriving it from the clock on
every render: re-rendering with the same value leaves the user's scroll position
alone, while a new value scrolls.

## Scroll to a time

To scroll on demand, such as from a "now" button, attach a ref to `Calendar` (or
`TimeGrid`) and call `scrollToTime` with minutes from midnight. Unlike
`scrollOffsetMinutes`, it scrolls every time you call it, even to the same time.
The scroll animates unless you pass `{ animated: false }` or the OS asks to
reduce motion, and it does nothing while a month, year, or schedule view is
showing.

```tsx theme={null}
import { useRef, useState } from "react";
import { Button } from "react-native";
import { Calendar, type CalendarEvent, type CalendarHandle } from "@super-calendar/native";

function WeekWithNowButton({ events }: { events: CalendarEvent[] }) {
  const [date, setDate] = useState(new Date());
  const calendar = useRef<CalendarHandle>(null);
  const scrollToNow = () => {
    const now = new Date();
    calendar.current?.scrollToTime(now.getHours() * 60 + now.getMinutes());
  };
  return (
    <>
      <Button title="Now" onPress={scrollToNow} />
      <Calendar ref={calendar} mode="week" date={date} events={events} onChangeDate={setDate} />
    </>
  );
}
```

## The hour axis

* `minHour` / `maxHour` — clamp the visible window (e.g. 7–20) instead of the
  full day.
* `hourHeight` — initial pixels per hour.
* Zooming rescales it between `minHourHeight` and `maxHourHeight`: pinch on
  native, Ctrl/⌘ + wheel on the web.
* `timeslots` — sub-hour divider lines per hour (e.g. `2` for half-hours).
* `ampm` — 12-hour labels; `hourComponent` replaces the label entirely.
* `hideHours` — collapse the hour gutter (the grid lines stay).
* The hour column is a single column beside the day columns, in the same
  scroll view, so it scrolls and zooms with them and holds still while you
  swipe between pages. Style it through the `hourGutter` [slot](/guides/styling).
* `showWeekNumber` / `weekNumberPrefix` — ISO week number in the header gutter.
* `hiddenDays` — weekdays (0=Sunday…6=Saturday) dropped from the view, e.g.
  `[0, 6]` for a Monday–Friday business week. Count-based views keep their
  column count by skipping hidden days.

## Event boxes

A timed event's box is sized to its duration, with two guards you can tune:

* `minEventHeight` — the floor on a box's pixel height, so a 5-minute event
  stays legible and tappable. It is also the floor of the `boxHeight` passed to
  your [`renderEvent`](/guides/events#render-your-own-event). Default 32 on
  native, 14 on the dom renderer. Pass `0` to size every box strictly by its
  duration.
* `eventGap` — the inset in pixels between a box and its slot on each side, so
  adjacent boxes and column edges get some breathing room. Default 2 on native,
  1 on the dom renderer. Pass `0` to let events fill the full slot.

```tsx theme={null}
<Calendar
  mode="week"
  date={date}
  events={events}
  minEventHeight={0}
  eventGap={0}
  renderEvent={MyEvent}
  onChangeDate={setDate}
/>
```

## Pull to refresh

On React Native, `refreshControl` takes a `RefreshControl` element and wraps the
grid's vertical scroll view, so a pull from the top can reload the events. The
pull is only reachable with the grid scrolled to its very top, which the default
`scrollOffsetMinutes` starts you away from. On Android that same layout also
catches a page swipe with a downward component while sitting at the top, so it
refreshes instead of paging.

## The all-day lane

All-day events (flagged `allDay`, or spanning midnight-to-midnight) leave the
timed columns and stack in a lane above the grid, which both renderers drop
entirely for a week with no all-day events. On React Native the lane pages with
the day columns and stays pinned above the hours while you scroll, and its
height follows the week under it as you swipe. The "all-day" text label is off
by default so the lane can come and go without a stranded label; set
`showAllDayLabel` to bring it back. Turn the lane off entirely with
`showAllDayEventCell={false}`.

## Now line and business hours

The red current-time line follows the wall clock (`showNowIndicator`, on by
default). `businessHours` shades the closed hours per day; return `null` for a
fully closed day (see [Theming](/guides/theming) for the shade colour). Return an
array of windows to leave a closed gap between them, such as a lunch break:

```tsx theme={null}
// Open 9-12 and 13-17: the 12-13 lunch hour shades closed too.
businessHours={() => [
  { start: 9, end: 12 },
  { start: 13, end: 17 },
]}
```

To put your own content in the closed region (a label, an icon, a striped
pattern), add `renderBusinessHours`. The grid keeps positioning each band and
calls you with `{ date, start, end }` (fractional hours, clamped to the visible
window); the themed tint is dropped so your output owns the look. The band is
decorative: it stays non-interactive and hidden from assistive tech, so return
visuals, not buttons or announced text:

```tsx theme={null}
<Calendar
  mode="week"
  date={date}
  events={events}
  businessHours={() => ({ start: 9, end: 17 })}
  renderBusinessHours={({ start }) => <ClosedBand label={start === 0 ? "Opens 9am" : "Closed"} />}
  onChangeDate={setDate}
  onPressEvent={onPress}
/>
```

Saturday and Sunday columns are tinted with the weekend background by default. Pass
`highlightWeekends={false}` to treat them like any other day (or recolour the tint
via the `weekendBackground` [theme](/guides/theming) token).

## Interaction

Tap handlers: `onPressCell` / `onLongPressCell` (empty grid space),
`onPressEvent` / `onLongPressEvent`, and `onPressDateHeader` (the day-column
headers). Drag-to-move, resize, and drag-to-create are covered in
[Dragging & creating](/guides/dragging); keyboard and screen-reader support in
[Accessibility](/guides/accessibility).

Style parts of the grid with per-slot [classes](/guides/styling), or recolour it
via the [theme](/guides/theming).

## Custom header (React Native)

Three `Calendar` props customize the area above the grid; all are native-only
(the dom renderer styles its header through the `header` / `columnHeader*`
[slots](/guides/styling) instead).

* `renderTimeGridHeader={(days: Date[]) => ReactNode}` **replaces** the built-in
  day-header row with a single fixed header above the grid (it does not page).
  The week-number gutter and the tappable weekday/date buttons disappear, and
  your element renders full-width in their place. `days` is the visible page's
  dates in column order. The all-day lane and the grid itself stay. To line your
  columns up with the grid's, leave a leading spacer as wide as the hour gutter
  (`hourColumnWidth`, default 56, or 0 with `hideHours`). The built-in header,
  by contrast, pages with the columns.
* `headerComponent={<YourToolbar />}` **inserts** an element, unchanged, above
  the grid. It takes no arguments and replaces nothing, and it doesn't scroll
  with the hours. The built-in day header now pages with the columns, so
  `headerComponent` sits above that paged weekday/date row. Use it for a filter
  row, an avatar strip, or your own toolbar.
* `renderHeaderForMonthView={(weekDays: Date[]) => ReactNode}` is the month-grid
  equivalent of `renderTimeGridHeader`: it replaces the weekday-label header;
  return `null` to hide it.

```tsx theme={null}
<Calendar
  mode="week"
  date={date}
  events={events}
  headerComponent={
    <View style={{ flexDirection: "row", padding: 8 }}>
      <TeamFilter value={team} onChange={setTeam} />
    </View>
  }
  onChangeDate={setDate}
  onPressEvent={onPress}
/>
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.