or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

date-field-state.mddate-picker-state.mddate-range-picker-state.mdindex.mdtime-field-state.md

date-field-state.mddocs/

0

# Date Field State

1

2

State management for date field components with individually editable segments. Each part of a date value (year, month, day, hour, minute, second) is displayed in a separate editable segment, providing precise keyboard-based date and time input.

3

4

## Capabilities

5

6

### useDateFieldState Hook

7

8

Creates a state object for managing date field component state with segment-based editing, validation, and formatting.

9

10

```typescript { .api }

11

/**

12

* Provides state management for a date field component.

13

* A date field allows users to enter and edit date and time values using a keyboard.

14

* Each part of a date value is displayed in an individually editable segment.

15

* @param props - Configuration options including locale and calendar system

16

* @returns DateFieldState object with segment management and validation

17

*/

18

function useDateFieldState<T extends DateValue = DateValue>(

19

props: DateFieldStateOptions<T>

20

): DateFieldState;

21

22

interface DateFieldStateOptions<T extends DateValue = DateValue> extends DatePickerProps<T> {

23

/**

24

* The maximum unit to display in the date field.

25

* @default 'year'

26

*/

27

maxGranularity?: 'year' | 'month' | Granularity;

28

/** The locale to display and edit the value according to. */

29

locale: string;

30

/**

31

* A function that creates a Calendar object for a given calendar identifier.

32

* Such a function may be imported from the @internationalized/date package.

33

*/

34

createCalendar: (name: CalendarIdentifier) => Calendar;

35

}

36

37

interface DateFieldState extends FormValidationState {

38

/** The current field value. */

39

value: DateValue | null;

40

/** The default field value. */

41

defaultValue: DateValue | null;

42

/** The current value, converted to a native JavaScript Date object. */

43

dateValue: Date;

44

/** The calendar system currently in use. */

45

calendar: Calendar;

46

/** Sets the field's value. */

47

setValue(value: DateValue | null): void;

48

/** A list of segments for the current value. */

49

segments: DateSegment[];

50

/** A date formatter configured for the current locale and format. */

51

dateFormatter: DateFormatter;

52

/** The current validation state of the date field, based on the `validationState`, `minValue`, and `maxValue` props. @deprecated Use `isInvalid` instead. */

53

validationState: ValidationState | null;

54

/** Whether the date field is invalid, based on the `isInvalid`, `minValue`, and `maxValue` props. */

55

isInvalid: boolean;

56

/** The granularity for the field, based on the `granularity` prop and current value. */

57

granularity: Granularity;

58

/** The maximum date or time unit that is displayed in the field. */

59

maxGranularity: 'year' | 'month' | Granularity;

60

/** Whether the field is disabled. */

61

isDisabled: boolean;

62

/** Whether the field is read only. */

63

isReadOnly: boolean;

64

/** Whether the field is required. */

65

isRequired: boolean;

66

/** Increments the given segment. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit. */

67

increment(type: SegmentType): void;

68

/** Decrements the given segment. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit. */

69

decrement(type: SegmentType): void;

70

/** Increments the given segment by a larger amount, rounding it to the nearest increment. The amount to increment by depends on the field, for example 15 minutes, 7 days, and 5 years. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit. */

71

incrementPage(type: SegmentType): void;

72

/** Decrements the given segment by a larger amount, rounding it to the nearest increment. The amount to decrement by depends on the field, for example 15 minutes, 7 days, and 5 years. Upon reaching the minimum or maximum value, the value wraps around to the opposite limit. */

73

decrementPage(type: SegmentType): void;

74

/** Sets the value of the given segment. */

75

setSegment(type: 'era', value: string): void;

76

setSegment(type: SegmentType, value: number): void;

77

/** Updates the remaining unfilled segments with the placeholder value. */

78

confirmPlaceholder(): void;

79

/** Clears the value of the given segment, reverting it to the placeholder. */

80

clearSegment(type: SegmentType): void;

81

/** Formats the current date value using the given options. */

82

formatValue(fieldOptions: FieldOptions): string;

83

/** Gets a formatter based on state's props. */

84

getDateFormatter(locale: string, formatOptions: FormatterOptions): DateFormatter;

85

}

86

```

87

88

**Usage Examples:**

89

90

```typescript

91

import { useDateFieldState } from "@react-stately/datepicker";

92

import { CalendarDate, createCalendar } from "@internationalized/date";

93

94

// Basic date field

95

function BasicDateField() {

96

const state = useDateFieldState({

97

locale: 'en-US',

98

createCalendar,

99

defaultValue: new CalendarDate(2023, 6, 15),

100

onChange: (value) => console.log("Date changed:", value?.toString())

101

});

102

103

return (

104

<div>

105

{state.segments.map((segment, index) => (

106

<span

107

key={index}

108

style={{

109

padding: '2px',

110

backgroundColor: segment.isPlaceholder ? '#f0f0f0' : 'white',

111

border: segment.isEditable ? '1px solid #ccc' : 'none'

112

}}

113

>

114

{segment.text}

115

</span>

116

))}

117

<div>Current value: {state.value?.toString()}</div>

118

</div>

119

);

120

}

121

122

// Time field with segment manipulation

123

function TimeField() {

124

const state = useDateFieldState({

125

locale: 'en-US',

126

createCalendar,

127

granularity: 'second',

128

maxGranularity: 'hour',

129

onChange: (value) => console.log("Time:", value)

130

});

131

132

const handleSegmentIncrement = (segment: DateSegment) => {

133

if (segment.isEditable) {

134

state.increment(segment.type);

135

}

136

};

137

138

return (

139

<div>

140

{state.segments.map((segment, index) => (

141

<button

142

key={index}

143

disabled={!segment.isEditable}

144

onClick={() => handleSegmentIncrement(segment)}

145

style={{

146

margin: '1px',

147

padding: '4px',

148

backgroundColor: segment.isPlaceholder ? '#f0f0f0' : 'white'

149

}}

150

>

151

{segment.text}

152

</button>

153

))}

154

<div>

155

<button onClick={() => state.confirmPlaceholder()}>

156

Confirm Placeholder

157

</button>

158

</div>

159

</div>

160

);

161

}

162

163

// Date field with validation and custom formatting

164

function ValidatedDateField() {

165

const state = useDateFieldState({

166

locale: 'fr-FR',

167

createCalendar,

168

minValue: new CalendarDate(2020, 1, 1),

169

maxValue: new CalendarDate(2030, 12, 31),

170

shouldForceLeadingZeros: true,

171

isRequired: true,

172

onChange: (value) => {

173

if (value) {

174

console.log("Valid date:", state.formatValue({

175

year: 'numeric',

176

month: 'long',

177

day: 'numeric'

178

}));

179

}

180

}

181

});

182

183

return (

184

<div>

185

<div style={{ border: state.isInvalid ? '2px solid red' : '1px solid #ccc' }}>

186

{state.segments.map((segment, index) => (

187

<input

188

key={index}

189

value={segment.text}

190

placeholder={segment.placeholder}

191

readOnly={!segment.isEditable}

192

onChange={(e) => {

193

if (segment.type === 'era') {

194

state.setSegment(segment.type, e.target.value);

195

} else {

196

const num = parseInt(e.target.value);

197

if (!isNaN(num)) {

198

state.setSegment(segment.type, num);

199

}

200

}

201

}}

202

style={{

203

width: `${segment.text.length + 2}ch`,

204

border: 'none',

205

textAlign: 'center'

206

}}

207

/>

208

))}

209

</div>

210

{state.isInvalid && <div style={{ color: 'red' }}>Invalid date range</div>}

211

</div>

212

);

213

}

214

```

215

216

### Date Segment Interface

217

218

Each segment represents an individual editable part of the date/time value.

219

220

```typescript { .api }

221

interface DateSegment {

222

/** The type of segment. */

223

type: SegmentType;

224

/** The formatted text for the segment. */

225

text: string;

226

/** The numeric value for the segment, if applicable. */

227

value?: number;

228

/** The minimum numeric value for the segment, if applicable. */

229

minValue?: number;

230

/** The maximum numeric value for the segment, if applicable. */

231

maxValue?: number;

232

/** Whether the value is a placeholder. */

233

isPlaceholder: boolean;

234

/** A placeholder string for the segment. */

235

placeholder: string;

236

/** Whether the segment is editable. */

237

isEditable: boolean;

238

}

239

240

type SegmentType = 'era' | 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'dayPeriod' | 'literal' | 'timeZoneName';

241

```

242

243

### Segment Manipulation Methods

244

245

Methods for incrementing, decrementing, and setting individual segments.

246

247

```typescript { .api }

248

/**

249

* Increments the given segment by 1. Upon reaching the maximum value, wraps to minimum.

250

* @param type - The segment type to increment

251

*/

252

increment(type: SegmentType): void;

253

254

/**

255

* Decrements the given segment by 1. Upon reaching the minimum value, wraps to maximum.

256

* @param type - The segment type to decrement

257

*/

258

decrement(type: SegmentType): void;

259

260

/**

261

* Increments the given segment by a larger amount (page step).

262

* Page steps: year=5, month=2, day=7, hour=2, minute=15, second=15

263

* @param type - The segment type to increment

264

*/

265

incrementPage(type: SegmentType): void;

266

267

/**

268

* Decrements the given segment by a larger amount (page step).

269

* @param type - The segment type to decrement

270

*/

271

decrementPage(type: SegmentType): void;

272

273

/**

274

* Sets the value of a specific segment

275

* @param type - The segment type to set

276

* @param value - The value to set (string for era, number for others)

277

*/

278

setSegment(type: 'era', value: string): void;

279

setSegment(type: SegmentType, value: number): void;

280

281

/**

282

* Clears the value of the given segment, reverting it to placeholder

283

* @param type - The segment type to clear

284

*/

285

clearSegment(type: SegmentType): void;

286

287

/**

288

* Updates remaining unfilled segments with the placeholder value

289

* Useful for completing partial date entry

290

*/

291

confirmPlaceholder(): void;

292

```

293

294

### Calendar Integration

295

296

The date field integrates with different calendar systems through the @internationalized/date library.

297

298

```typescript { .api }

299

interface DateFieldStateOptions<T> {

300

/** The locale to display and edit the value according to. */

301

locale: string;

302

/**

303

* A function that creates a Calendar object for a given calendar identifier.

304

* Such a function may be imported from the @internationalized/date package.

305

*/

306

createCalendar: (name: CalendarIdentifier) => Calendar;

307

}

308

```

309

310

Example calendar setup:

311

312

```typescript

313

import { createCalendar } from "@internationalized/date";

314

315

const state = useDateFieldState({

316

locale: 'ar-SA', // Arabic Saudi Arabia

317

createCalendar, // Supports Gregory, Islamic, Buddhist, etc.

318

// ... other props

319

});

320

```

321

322

### Granularity Control

323

324

Control which date/time segments are displayed and editable.

325

326

```typescript { .api }

327

interface DateFieldStateOptions<T> {

328

/**

329

* The maximum unit to display in the date field.

330

* @default 'year'

331

*/

332

maxGranularity?: 'year' | 'month' | Granularity;

333

/** Determines the smallest unit that is displayed in the date picker. */

334

granularity?: Granularity;

335

}

336

```

337

338

Examples:

339

- `granularity: 'day'` - Shows year, month, day

340

- `granularity: 'minute', maxGranularity: 'day'` - Shows day, hour, minute

341

- `granularity: 'second'` - Shows all segments including seconds