> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Date Field Yearless Range - Web

> A form field for selecting a date range without year information, useful for recurring date ranges.

> [!NOTE]
>
> For development, import `DateFieldYearlessRange` from
> `@servicetitan/anvil2`. For design, find it in the
> [Anvil2 file](https://www.figma.com/design/xaNQsvRKczoxu7pj0M6QT8/Anvil2-v3?node-id=2033-10622).

![](https://mintcdn.com/servicetitan/66tZkkkyD48ugyZL/images/docs/web/components/date-field-yearless-range/overview-image.png?fit=max\&auto=format\&n=66tZkkkyD48ugyZL\&q=85\&s=a1170612f97355cc905d9768707d3d41)

## Anatomy

Date Field Yearless Range consists of seven primary elements that enable users to select a start and end date without year information.

![Anatomy of the Date Field Yearless Range component](https://mintcdn.com/servicetitan/66tZkkkyD48ugyZL/images/docs/web/components/date-field-yearless-range/design/date-field-yearless-range-anatomy.png?fit=max\&auto=format\&n=66tZkkkyD48ugyZL\&q=85\&s=4f77d71fac2255dc99098c284e68002c)

1. **Label** - Identifies the field and its purpose
2. **Start date input** - Text input for manual start date entry with format mask
3. **End date input** - Text input for manual end date entry with format mask
4. **Helper text** (Optional) - Description, format hint or error message

## Options

Date Field Yearless Range supports the following configurations to accommodate different use cases and regional preferences.

### Date Format Modes

datefieldyearlessrange-mode

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-mode?file=src/App.tsx)

```tsx lines theme={null}
import { DateFieldYearlessRange, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column" gap="4" style={{ minWidth: "384px" }}>
      {/** US format (default) */}
      <DateFieldYearlessRange label="US Format" mode="mm/dd" />

      {/** International format */}
      <DateFieldYearlessRange label="International Format" mode="dd/mm" />
    </Flex>
  );
}

export default App;
```

Date Field Yearless Range supports two date format modes to match regional conventions. The default format is `mm/dd` for US audiences, while `dd/mm` is available for international users.

| Mode | Format | Use Case |
| - | - | - |
| mm/dd | Default | US date format |
| dd/mm | Optional | International date format |

### Sizes

datefieldyearlessrange-size

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-size?file=src/App.tsx)

```tsx lines theme={null}
import { DateFieldYearlessRange, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column" gap="4" style={{ minWidth: "384px" }}>
      <DateFieldYearlessRange label="Small" size="small" />
      <DateFieldYearlessRange label="Medium" size="medium" />
      <DateFieldYearlessRange label="Large" size="large" />
    </Flex>
  );
}

export default App;
```

Three size options accommodate different layout densities and visual hierarchies.

| Size | Height |
| - | - |
| Small | 32px |
| Medium | 40px |
| Large | 48px |

### Date Picker

datefieldyearlessrange-disablepicker

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-disablepicker?file=src/App.tsx)

```tsx lines theme={null}
import { DateFieldYearlessRange } from "@servicetitan/anvil2";

function App() {
  return (
    <DateFieldYearlessRange
      label="Seasonal Period"
      disablePicker
      description="Calendar picker is disabled, manual entry only"
    />
  );
}

export default App;
```

The date picker can be disabled when manual text entry is preferred or when the picker interface is not suitable for the use case.

## Behavior

Date Field Yearless Range responds to user interaction with distinct visual states and validation feedback.

### Visual States

datefieldyearlessrange-visual-states

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-visual-states?file=src/App.tsx)

```tsx lines theme={null}
import { DateFieldYearlessRange, Grid } from "@servicetitan/anvil2";

function App() {
  return (
    <Grid gap="6">
      <DateFieldYearlessRange
        label="Seasonal Period"
        defaultValue={{
          startDate: { month: 6, day: 1 },
          endDate: { month: 8, day: 31 },
        }}
        required
      />
      <DateFieldYearlessRange
        label="Seasonal Period"
        defaultValue={{
          startDate: { month: 6, day: 1 },
          endDate: { month: 8, day: 31 },
        }}
        required
        disabled
      />
      <DateFieldYearlessRange
        label="Seasonal Period"
        defaultValue={{
          startDate: { month: 8, day: 31 },
          endDate: { month: 6, day: 1 },
        }}
        required
        error="End date must be after start date"
      />
    </Grid>
  );
}

export default App;
```

The component displays different visual states to communicate field status and interactivity. Default state shows both fields ready for input. Focus state highlights the active field. Error state displays validation messages when date ranges are invalid, start dates are after end dates, or required fields are empty. Disabled state prevents interaction while maintaining visual context.

### Date Picker Interaction

Clicking either input field opens a popover with two scrollable lists for month and day selection. Users can scroll through months and days and select values directly from the lists. The picker closes automatically after selection, and the selected month and day populate the respective input field.

### Validation

datefieldyearlessrange-error

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-error?file=src/App.tsx)

```tsx lines theme={null}
import { DateFieldYearlessRange } from "@servicetitan/anvil2";

function App() {
  return (
    <DateFieldYearlessRange
      label="Date Range"
      error="End date must be after start date"
      required
    />
  );
}

export default App;
```

Date Field Yearless Range validates input in real time. The component checks for parseable month and day values, required field completion, date constraints (min/max dates), unavailable dates, and logical range validation (start date must be before or equal to end date). Error messages appear below the fields when validation fails.

## Usage Guidelines

| Standard | Requirement |
| - | - |
| DoCapturing recurring date ranges | Capture recurring date ranges where year is irrelevant |
| DoSelecting seasonal periods | Select seasonal periods or annual date ranges |
| DoInputting recurring annual events | Input date ranges for recurring annual events |
| DoCreating date range templates | Create date range templates for annual use |
| DoLabel yearless ranges clearly | Write labels that clearly indicate year isn't needed, include format hints, validate the range, and maintain consistency alongside year-specific ranges; see [Labeling and Yearless Range Validation](#labeling-and-yearless-range-validation). |
| Don'tSpecific date ranges with year | Use [Date Field Range](https://anvil.servicetitan.com/docs/components/date-field-range/web.md) instead |
| Don'tSingle dates | Use [Date Field Single](https://anvil.servicetitan.com/docs/components/date-field-single/web.md) or [Date Field Yearless](https://anvil.servicetitan.com/docs/components/date-field-yearless/web.md) instead |
| Don'tTime selection | Use [Time Field](https://anvil.servicetitan.com/docs/components/time-field/web.md) for time-only inputs |
| Don'tAmbiguous context or invalid ranges | Don't use Date Field Yearless Range for ranges that require year information or allow invalid ranges without clear feedback; see [Anti-pattern: Ambiguous Context and Invalid Ranges](#anti-pattern%3A-ambiguous-context-and-invalid-ranges). |

### Alternatives

#### Date Field Yearless Range vs Date Field Range

Use Date Field Yearless Range when the year is irrelevant to the date range selection, such as recurring seasonal periods or annual date templates. Use Date Field Range when the year is essential, such as project timelines or reporting periods.

### How to Use

#### Labeling and Yearless Range Validation

Provide clear, descriptive labels that communicate the purpose of the date range selection and indicate that year information is not required. Labels should clarify that only month and day ranges are needed, helping users understand why year input is omitted. Implement validation that ensures logical date ranges and provides immediate feedback when constraints are violated.

datefieldyearlessrange-seasonal-period

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-seasonal-period?file=src/App.tsx)

```tsx lines theme={null}
import { DateFieldYearlessRange } from "@servicetitan/anvil2";

function App() {
  return (
    <DateFieldYearlessRange
      label="Recurring Date Range"
      description="Enter month and day range only (year not required)"
      required
    />
  );
}

export default App;
```

**Do**

* Write labels that clearly communicate the purpose and indicate year is not needed
* Include format hints to guide users on expected input format (mm/dd or dd/mm)
* Set appropriate date constraints (min/max dates) when applicable to prevent invalid selections
* Validate that start date is before or equal to end date
* Display validation errors immediately when they occur
* Use Date Field Yearless Range for recurring date ranges where year context is not needed
* Maintain consistency when using yearless ranges alongside year-specific ranges in forms

#### Anti-pattern: Ambiguous Context and Invalid Ranges

Avoid creating confusion by using Date Field Yearless Range for ranges that require year information or allowing invalid date ranges without clear feedback.

datefieldyearlessrange-specific-ranges-dont

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-specific-ranges-dont?file=src/App.tsx)

```tsx lines theme={null}
import { DateFieldYearlessRange } from "@servicetitan/anvil2";

function App() {
  return <DateFieldYearlessRange label="Timeline" required />;
}

export default App;
```

**Don’t**

* Use Date Field Yearless Range for date ranges that require year information
* Omit format hints when the date format might be ambiguous to users
* Hide validation errors until form submission
* Allow start dates to be after end dates without clear error messaging
* Use placeholder text to communicate date format instead of format hints
* Mix yearless date ranges with year-specific date ranges in the same form without clear visual or contextual distinction
* Create labels that don't indicate year is not required

## Content

Content within Date Field Yearless Range should be clear, concise, and actionable.

* Labels should clearly indicate what date range is being selected and that year is not required
* Error messages should explain why a date range is invalid and how to fix it
* Format hints should match the selected mode (mm/dd or dd/mm)
* Descriptions should provide context without overwhelming the user

## Keyboard Interaction

Users can navigate Date Field Yearless Range using standard keyboard controls.

### Input Fields

| Key | Description |
| - | - |
| Tab | Moves focus between start and end date inputs |
| Shift + Tab | Moves focus to the previous element |
| Arrow Down | Opens the date picker when focused |
| Esc | Closes the date picker |

### Date Picker

| Key | Description |
| - | - |
| Arrow Up | Moves focus to the previous item in the list |
| Arrow Down | Moves focus to the next item in the list |
| Esc | Closes the date picker |

### Accessibility

Date Field Yearless Range includes built-in accessibility features. The component uses semantic grouping to associate the start and end date inputs. The component supports full keyboard navigation and screen reader compatibility. Ensure labels are descriptive and error messages are clear for assistive technology users.

For more guidance on form field labels and context, see [input field context association best practices](https://anvil.servicetitan.com/docs/accessibility/labels-and-ctas.md#input-field-context-association).

## Code

**Implementation**

datefieldyearlessrange-playground

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-playground?file=src/App.tsx)

```tsx lines expandable theme={null}
import { DateFieldYearlessRange } from "@servicetitan/anvil2";

function App() {
  return <DateFieldYearlessRange label="Date Range" />;
}

export default App;
```

## Common Examples

```tsx theme={null}
import { DateFieldYearlessRange } from "@servicetitan/anvil2";

function ExampleComponent() {
  return <DateFieldYearlessRange label="Date Range" />;
}
```

### Controlled vs Uncontrolled

The `DateFieldYearlessRange` component can be used in controlled or uncontrolled mode.

#### Uncontrolled

Use `defaultValue` to set an initial value without controlling the state.

datefieldyearlessrange-uncontrolled

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-uncontrolled?file=src/App.tsx)

```tsx lines expandable theme={null}
import { DateFieldYearlessRange } from "@servicetitan/anvil2";

function App() {
  return (
    <DateFieldYearlessRange
      label="Season"
      defaultValue={{
        startDate: { month: 6, day: 1 },
        endDate: { month: 8, day: 31 },
      }}
    />
  );
}

export default App;
```

#### Controlled

Use `value` and `onChange` for full control over the component state.

datefieldyearlessrange-controlled

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-controlled?file=src/App.tsx)

```tsx lines expandable theme={null}
import {
  DateFieldYearlessRange,
  type DateFieldYearlessRangeChange,
} from "@servicetitan/anvil2";
import { useState } from "react";

function App() {
  const [dateRange, setDateRange] = useState<DateFieldYearlessRangeChange>({
    startDate: { month: 1, day: 1 },
    endDate: { month: 12, day: 31 },
  });

  return (
    <DateFieldYearlessRange
      label="Annual Period"
      value={dateRange}
      onChange={setDateRange}
    />
  );
}

export default App;
```

### Date Format Modes

The component supports two date format modes: `mm/dd` (default) and `dd/mm`.

datefieldyearlessrange-mode

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-mode?file=src/App.tsx)

```tsx lines expandable theme={null}
import { DateFieldYearlessRange, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column" gap="4" style={{ minWidth: "384px" }}>
      {/** US format (default) */}
      <DateFieldYearlessRange label="US Format" mode="mm/dd" />

      {/** International format */}
      <DateFieldYearlessRange label="International Format" mode="dd/mm" />
    </Flex>
  );
}

export default App;
```

### With Validation

Show error states when validation fails.

datefieldyearlessrange-error

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-error?file=src/App.tsx)

```tsx lines expandable theme={null}
import { DateFieldYearlessRange } from "@servicetitan/anvil2";

function App() {
  return (
    <DateFieldYearlessRange
      label="Date Range"
      error="End date must be after start date"
      required
    />
  );
}

export default App;
```

### Sizes

The component supports `small`, `medium`, and `large` sizes.

datefieldyearlessrange-size

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-size?file=src/App.tsx)

```tsx lines expandable theme={null}
import { DateFieldYearlessRange, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column" gap="4" style={{ minWidth: "384px" }}>
      <DateFieldYearlessRange label="Small" size="small" />
      <DateFieldYearlessRange label="Medium" size="medium" />
      <DateFieldYearlessRange label="Large" size="large" />
    </Flex>
  );
}

export default App;
```

### Custom Labels

Customize the accessible labels for the start and end date fields.

datefieldyearlessrange-label

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-label?file=src/App.tsx)

```tsx lines expandable theme={null}
import { DateFieldYearlessRange } from "@servicetitan/anvil2";

function App() {
  return (
    <DateFieldYearlessRange
      label="Service Period"
      startLabel="Service starts"
      endLabel="Service ends"
    />
  );
}

export default App;
```

## React Accessibility

* The component uses a `fieldset` with a `legend` for proper grouping
* Start and end date fields have individual accessible labels (visually hidden)
* Error messages are announced via `aria-live`
* The `moreInfo` tooltip content is also available to screen readers

For more guidance on form field labels and context, see [input field context association best practices](https://anvil.servicetitan.com/docs/accessibility/labels-and-ctas.md#input-field-context-association).

### Markdown in labels

The `label` prop supports inline markdown: bold (`**text**`), italic (`*text*`), bold and italic (`***text***`), highlight (`==text==`), and code (`` `text` ``).

datefieldyearlessrange-markdownlabel

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-markdownlabel?file=src/App.tsx)

```tsx lines expandable theme={null}
import { DateFieldYearlessRange, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column" gap="4" style={{ maxWidth: 500 }}>
      <DateFieldYearlessRange label="**Bold** label" />
      <DateFieldYearlessRange label="*Italic* label" />
      <DateFieldYearlessRange label="***Bold and italic*** label" />
      <DateFieldYearlessRange label="==Highlight== label" />
      <DateFieldYearlessRange label="`Code` label" />
    </Flex>
  );
}

export default App;
```

### Hide the label

Use `hideLabel` to visually hide the label. The `label` string is kept as a screen-reader-only `<legend>` element so the group remains accessible — any inline markdown is stripped to plain text.

datefieldyearlessrange-hidelabel

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/datefieldyearlessrange-hidelabel?file=src/App.tsx)

```tsx lines expandable theme={null}
import { DateFieldYearlessRange } from "@servicetitan/anvil2";

function App() {
  return <DateFieldYearlessRange label="Service period" hideLabel />;
}

export default App;
```

## Testing

Interactive sub-elements carry a stable `data-anv-part` attribute so end-to-end tests can target them. Attach your own `data-*` (such as `data-cy`) to the field — it is forwarded to the fieldset root:

```tsx theme={null}
<DateFieldYearlessRange data-cy="service-period" label="Service period" />
```

```ts theme={null}
cy.get('[data-cy="service-period"] [data-anv-part="start-input"]').type("01/01");
cy.get('[data-cy="service-period"] [data-anv-part="end-input"]').type("12/31");
```

| `data-anv-part` | Element |
| - | - |
| `start-input` | Start masked month/day input |
| `end-input` | End masked month/day input |

The shared yearless picker also stamps `popover`, `month-list`, `day-list`, and `option` (see Date Field Yearless Testing). Those parts render in the top layer and are not descendants of the fieldset.

**DateFieldYearlessRange Props**

```tsx theme={null}
<DateFieldYearlessRange
  label="Date Range"
  mode="mm/dd"
  value={{ startDate: { month: 6, day: 1 }, endDate: { month: 8, day: 31 } }}
  onChange={(change) => console.log(change)}
  required={false}
  error={false}
  size="medium"
/>
```

## `DateFieldYearlessRange` Props

The `DateFieldYearlessRange` component accepts the following props as well as layout utility props.

**label** `string` *required*

Label for the field. Supports inline markdown formatting.

**defaultValue** `DateFieldYearlessRangeValue`

Default value for uncontrolled usage. Object with `startDate` and `endDate` properties, each containing `month` and `day` numbers.

**description** `ReactElement | string`

Helper text displayed below the input.

**disabled** `boolean`

Whether the field is disabled.

**disableHint** `boolean`

Whether to hide the format hint (e.g., "Format: mm/dd").

**disablePicker** `boolean`

Whether to disable the date picker popup.

**endLabel** `string` (default: End date)

Accessible label for the end date input (visually hidden).

**error** `ReactElement | string | boolean`

Error message or error state for the field.

**errorAriaLive** `"off" | "polite" | "assertive"` (default: assertive)

The `aria-live` value for error messages.

**hideLabel** `boolean` (default: false)

Visually hides the label while keeping it accessible to screen readers.

**id** `string`

Custom ID for the field.

**legendProps** `Omit\<FieldLabelProps, "el"\>`

Additional props to pass to the legend [FieldLabel](https://anvil.servicetitan.com/docs/components/field-label/code) component. Supports the `aiMark` prop for displaying [AI-powered field indicators](https://anvil.servicetitan.com/docs/utilities/web/ai-marks.md).

**mode** `"mm/dd" | "dd/mm"` (default: mm/dd)

The date format mode.

**moreInfo** `ReactNode`

Additional information to display in a tooltip next to the label.

**onBlur** `(event: React.FocusEvent) =\> void`

Callback when the field loses focus.

**onChange** `(change: DateFieldYearlessRangeChange) =\> void`

Callback when the date range value changes.

**onFocus** `(event: React.FocusEvent) =\> void`

Callback when the field receives focus.

**required** `boolean`

Whether the field is required.

**size** `"small" | "medium" | "large"`

The size of the input fields.

**startLabel** `string` (default: Start date)

Accessible label for the start date input (visually hidden).

**value** `DateFieldYearlessRangeValue`

Controlled value. Object with `startDate` and `endDate` properties, each containing `month` and `day` numbers or `null`.

### Types

```tsx theme={null}
type YearlessDate = {
  month: number; // 1-12
  day: number;   // 1-31
};

type DateFieldYearlessRangeValue = {
  startDate: YearlessDate | null;
  endDate: YearlessDate | null;
};

type DateFieldYearlessRangeChange = {
  startDate: YearlessDate | null;
  endDate: YearlessDate | null;
};
```


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