Navigation Patterns
Learn how to navigate through time periods using useTemporal's navigation functions: next, previous, and go.
Core Navigation Functions
next() - Move Forward
Navigate to the immediately following period:
typescript
const tomorrow = next(temporal.adapter, today)
const nextMonth = next(temporal.adapter, currentMonth)
const nextYear = next(temporal.adapter, currentYear)1
2
3
2
3
previous() - Move Backward
Navigate to the immediately preceding period:
typescript
const yesterday = previous(temporal.adapter, today)
const lastMonth = previous(temporal.adapter, currentMonth)
const lastYear = previous(temporal.adapter, currentYear)1
2
3
2
3
go() - Jump Multiple Steps
Navigate multiple periods in either direction:
typescript
const nextWeek = go(temporal.adapter, today, 7) // 7 days forward
const lastWeek = go(temporal.adapter, today, -7) // 7 days backward
const quarterAhead = go(temporal.adapter, month, 3) // 3 months forward1
2
3
2
3
Common Navigation Patterns
Calendar Navigation Controls
typescript
function CalendarControls({ temporal }) {
const period = temporal.browsing
const handlePrevious = () => {
temporal.browsing.value = previous(temporal.adapter, period.value)
}
const handleNext = () => {
temporal.browsing.value = next(temporal.adapter, period.value)
}
const handleToday = () => {
temporal.browsing.value = temporal.period(
temporal.now.value.date,
period.value.type
)
}
return (
<div className="calendar-controls">
<button onClick={handlePrevious}>Previous</button>
<button onClick={handleToday}>Today</button>
<button onClick={handleNext}>Next</button>
</div>
)
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Keyboard Navigation
typescript
function useKeyboardNavigation(temporal: Temporal) {
useEffect(() => {
const handleKeyPress = (e: KeyboardEvent) => {
const current = temporal.browsing.value
switch(e.key) {
case 'ArrowLeft':
temporal.browsing.value = previous(temporal.adapter, current)
break
case 'ArrowRight':
temporal.browsing.value = next(temporal.adapter, current)
break
case 'ArrowUp':
// Navigate to larger unit
if (current.type === 'day') {
temporal.browsing.value = temporal.period( current.date, 'week')
} else if (current.type === 'week') {
temporal.browsing.value = temporal.period( current.date, 'month')
}
break
case 'ArrowDown':
// Navigate to smaller unit
if (current.type === 'month') {
temporal.browsing.value = temporal.period( current.date, 'week')
} else if (current.type === 'week') {
temporal.browsing.value = temporal.period( current.date, 'day')
}
break
}
}
document.addEventListener('keydown', handleKeyPress)
return () => document.removeEventListener('keydown', handleKeyPress)
}, [temporal])
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Date Range Generation
Generate sequences of periods for various use cases:
typescript
// Generate next N periods
function getNextPeriods(
start: Period,
count: number,
temporal: Temporal
): Period[] {
const periods = [start]
let current = start
for (let i = 1; i < count; i++) {
current = next(temporal.adapter, current)
periods.push(current)
}
return periods
}
// Generate periods between dates
function getPeriodsBetween(
start: Date,
end: Date,
unit: Unit,
temporal: Temporal
): Period[] {
const periods = []
let current = temporal.period( start, unit)
const endPeriod = temporal.period( end, unit)
while (current.start <= endPeriod.start) {
periods.push(current)
current = next(temporal.adapter, current)
}
return periods
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Infinite Scroll Calendar
typescript
function InfiniteCalendar({ temporal }) {
const [months, setMonths] = useState<Period[]>([])
const [centerMonth, setCenterMonth] = useState(temporal.browsing.value)
// Load months around center
useEffect(() => {
const before = []
const after = []
let current = centerMonth
// Load 3 months before
for (let i = 0; i < 3; i++) {
current = previous(temporal.adapter, current)
before.unshift(current)
}
// Load 3 months after
current = centerMonth
for (let i = 0; i < 3; i++) {
current = next(temporal.adapter, current)
after.push(current)
}
setMonths([...before, centerMonth, ...after])
}, [centerMonth, temporal])
// Handle scroll to load more
const handleScroll = (direction: 'up' | 'down') => {
if (direction === 'up') {
const firstMonth = months[0]
const prevMonth = previous(temporal.adapter, firstMonth)
setMonths([prevMonth, ...months.slice(0, -1)])
} else {
const lastMonth = months[months.length - 1]
const nextMonth = next(temporal.adapter, lastMonth)
setMonths([...months.slice(1), nextMonth])
}
}
return (
<div onScroll={handleScroll}>
{months.map(month => (
<MonthView key={month.date.toISOString()} month={month} />
))}
</div>
)
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Advanced Navigation
Custom Period Navigation
Navigation works seamlessly with custom periods:
typescript
const sprint = period(
temporal,
{
start: new Date('2024-01-01'),
end: new Date('2024-01-14')
}
)
// Next sprint (same duration)
const nextSprint = next(temporal.adapter, sprint)
// Results in: Jan 15 - Jan 28 (14 days)
// Navigate multiple sprints
const futureSprint = go(temporal.adapter, sprint, 5)
// Results in: 5 sprints ahead1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Boundary-Aware Navigation
Handle special cases like month boundaries:
typescript
// Navigate months while preserving day
function navigateMonth(
current: Date,
direction: 1 | -1,
temporal: Temporal
): Date {
const currentDay = current.getDate()
const targetMonth = go(
temporal,
temporal.period( current, 'month'),
direction
)
// Try to preserve the day
const targetDate = new Date(targetMonth.date)
targetDate.setDate(currentDay)
// Handle month overflow (e.g., Jan 31 -> Feb 31)
if (targetDate.getMonth() !== targetMonth.date.getMonth()) {
// Use last day of month instead
targetDate.setDate(0)
}
return targetDate
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Unit-Switching Navigation
Navigate while changing time units:
typescript
function SmartNavigation({ temporal }) {
const switchToUnit = (unit: Unit) => {
const current = temporal.browsing.value
temporal.browsing.value = temporal.period( current.date, unit)
}
const zoomIn = () => {
const current = temporal.browsing.value
const mapping: Record<Unit, Unit> = {
'year': 'month',
'month': 'week',
'week': 'day',
'day': 'hour'
}
const nextUnit = mapping[current.type]
if (nextUnit) {
switchToUnit(nextUnit)
}
}
const zoomOut = () => {
const current = temporal.browsing.value
const mapping: Record<Unit, Unit> = {
'hour': 'day',
'day': 'week',
'week': 'month',
'month': 'year'
}
const nextUnit = mapping[current.type]
if (nextUnit) {
switchToUnit(nextUnit)
}
}
return (
<div>
<button onClick={zoomOut}>Zoom Out</button>
<button onClick={zoomIn}>Zoom In</button>
</div>
)
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Performance Tips
Batch Navigation
When navigating multiple periods, batch operations:
typescript
// Instead of multiple reactive updates
const periods = []
let current = start
for (let i = 0; i < 100; i++) {
current = next(temporal.adapter, current)
periods.push(current)
temporal.browsing.value = current // Triggers update each time
}
// Batch the navigation
const periods = []
let current = start
for (let i = 0; i < 100; i++) {
current = next(temporal.adapter, current)
periods.push(current)
}
temporal.browsing.value = current // Single update1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Preload Adjacent Periods
For smooth navigation, preload adjacent periods:
typescript
const usePreloadedNavigation = (temporal: Temporal) => {
const current = computed(() => temporal.browsing.value)
const preloaded = computed(() => ({
prev: previous(temporal.adapter, current.value),
current: current.value,
next: next(temporal.adapter, current.value)
}))
const navigateNext = () => {
temporal.browsing.value = preloaded.value.next
}
const navigatePrev = () => {
temporal.browsing.value = preloaded.value.prev
}
return { navigateNext, navigatePrev, preloaded }
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
See Also
- API: next() - Next function reference
- API: previous() - Previous function reference
- API: go() - Go function reference
- Calendar Examples - Navigation in practice
- Keyboard Shortcuts - Keyboard navigation