> ## 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 – Code

> Field for choosing a recurring or template date

export const LiveCode = ({children, customHeight, clickToLoad, example, fullWidth, fullHeight, hideCodeInLiveCode, screenshot, screenshotOnly, showCode: showCodeProp}) => {
  const SCREENSHOTS_BASE = "https://servicetitan.github.io/anvil2-docs-live-code/screenshots";
  const STACKBLITZ_BASE = "https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples";
  const [showCodeBlock, setShowCodeBlock] = useState(showCodeProp ?? false);
  const [isLocalOverride, setIsLocalOverride] = useState(false);
  useEffect(() => {
    const examplePath = `/images/live-code-screenshots-tmp/${example}.png`;
    fetch(examplePath, {
      method: "HEAD"
    }).then(r => {
      if (r.ok) setIsLocalOverride(true);
    }).catch(() => {});
  }, [example]);
  const screenshotBase = isLocalOverride ? "/images/live-code-screenshots-tmp" : SCREENSHOTS_BASE;
  if (screenshotOnly) {
    return <Frame className="flex flex-col">
        <div className="flex dark:hidden" style={{
      justifyContent: "center",
      alignItems: "center",
      width: fullWidth ? "100%" : "50%",
      minHeight: fullHeight ? "284px" : undefined,
      background: "#FFFFFF"
    }}>
          <img srcset={`${screenshotBase}/${example}.png, ${screenshotBase}/${example}-2x.png 2x`} src={`${screenshotBase}/${example}.png`} alt={example} noZoom />
        </div>
        <div className="hidden dark:flex" style={{
      justifyContent: "center",
      alignItems: "center",
      width: fullWidth ? "100%" : "50%",
      minHeight: fullHeight ? "284px" : undefined,
      background: "#141414"
    }}>
          <img srcset={`${screenshotBase}/${example}-dark.png, ${screenshotBase}/${example}-dark-2x.png 2x`} src={`${screenshotBase}/${example}-dark.png`} alt={example} noZoom />
        </div>
      </Frame>;
  }
  if (screenshot) {
    return <Frame className="flex flex-col -mb-2">
        <div className="flex dark:hidden bg-white dark:bg-codeblock border border-gray-950/10 dark:border-white/10 dark:twoslash-dark rounded-2xl overflow-hidden" style={{
      justifyContent: "center",
      alignItems: "center",
      width: fullWidth ? "100%" : "50%",
      minHeight: fullHeight ? "284px" : undefined
    }}>
          <img srcset={`${screenshotBase}/${example}.png, ${screenshotBase}/${example}-2x.png 2x`} src={`${screenshotBase}/${example}.png`} alt={example} noZoom />
        </div>

        <div className="hidden dark:flex bg-white dark:bg-codeblock border border-gray-950/10 dark:border-white/10 dark:twoslash-dark rounded-2xl overflow-hidden" style={{
      background: "#141414",
      justifyContent: "center",
      alignItems: "center",
      width: fullWidth ? "100%" : "50%",
      minHeight: fullHeight ? "284px" : undefined
    }}>
          <img srcset={`${screenshotBase}/${example}-dark.png, ${screenshotBase}/${example}-dark-2x.png 2x`} src={`${screenshotBase}/${example}-dark.png`} alt={example} noZoom />
        </div>

        <div className="flex justify-end items-center text-xs py-2 px-1 gap-4">
          {!showCodeProp ? <button className="inline-flex justify-end items-center text-gray-700 dark:text-gray-50 hover:text-blue-500 dark:hover:text-blue-300 transition-colors group self-end gap-1 cursor-pointer" onClick={() => setShowCodeBlock(!showCodeBlock)} style={{
      appearance: "none"
    }}>
              <Icon icon="code" size="12px" className="group-hover:bg-blue-500 dark:group-hover:bg-blue-300" />
              <span>{showCodeBlock ? "Hide code" : "Show code"}</span>
            </button> : null}

          <a className="inline-flex justify-end items-center hover:text-blue-500 dark:hover:text-blue-300 transition-colors group self-end gap-1" href={`${STACKBLITZ_BASE}/${example}?file=src/App.tsx`} target="_blank" rel="noreferrer">
            <Icon icon="bolt" size="12px" className="group-hover:bg-blue-500 dark:group-hover:bg-blue-300" />
            <span>StackBlitz demo</span>
          </a>
        </div>

        <div className="grid transition-[grid-template-rows] duration-300 ease-in-out overflow-auto overflow-y-hidden overflow-x-auto" style={showCodeBlock ? {
      gridTemplateRows: "1fr"
    } : {
      gridTemplateRows: "0fr"
    }}>
          <div style={{
      minHeight: 0,
      overflowX: "auto",
      overflowY: "hidden",
      marginBlockStart: "-1.25rem",
      marginBlockEnd: "-1.5rem"
    }}>
            {children}
          </div>
        </div>
      </Frame>;
  } else {
    return <div style={{
      display: "flex",
      width: fullWidth ? "100%" : "50%",
      minHeight: customHeight ? customHeight : "316px",
      resize: "vertical",
      overflow: "auto"
    }}>
        <iframe title={example} style={{
      flex: 1,
      width: fullWidth ? "100%" : "50%",
      minHeight: customHeight ? customHeight : "316px"
    }} src={`${STACKBLITZ_BASE}/${example}?embed=1&hideNavigation=1&hideExplorer=1&terminalHeight=0&file=src/App.tsx${clickToLoad ? "&ctl=1" : ""}${hideCodeInLiveCode ? "&view=preview" : ""}`} allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" />
      </div>;
  }
};

<Tabs>
  <Tab title="Implementation">
    <LiveCode showCode example="datefieldyearless-playground" fullWidth screenshot>
      ```tsx lines expandable theme={null}
      import { DateFieldYearless } from "@servicetitan/anvil2";

      function App() {
        return <DateFieldYearless />;
      }

      export default App;
      ```
    </LiveCode>

    ## Common Examples

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

    function ExampleComponent() {
      return <DateFieldYearless defaultValue={{ month: 3, day: 22 }} />;
    }
    ```

    ### Default values

    Default values can be included in `DateFieldYearless` to use the field in an uncontrolled mode.

    <LiveCode showCode example="datefieldyearless-defaultvalue" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { DateFieldYearless } from "@servicetitan/anvil2";

      function App() {
        return <DateFieldYearless defaultValue={{ month: 12, day: 25 }} />;
      }

      export default App;
      ```
    </LiveCode>

    ## Controlled usage

    The `DateFieldYearless` can be controlled. This means you can maintain the state outside the component. Listen for new dates with `onChange` and supply a date into the `value` prop.

    <LiveCode showCode example="datefieldyearless-controlled" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import {
        DateFieldYearless,
        Flex,
        Button,
        type YearlessDate,
      } from "@servicetitan/anvil2";
      import { useState } from "react";

      function App() {
        const [value, setValue] = useState<YearlessDate | null>();

        return (
          <Flex gap={4}>
            <DateFieldYearless
              value={value}
              onChange={(change) => setValue(change.value)}
            />
            <Button
              onClick={() => {
                setValue({ day: 1, month: 1 });
              }}
            >
              Set to New Year&apos;s Day
            </Button>
          </Flex>
        );
      }

      export default App;
      ```
    </LiveCode>

    ### Validation

    Understanding the object passed back in `onChange` is key to understanding how to validate this field.

    `isValid` will tell you if the field can be parsed into a valid month and day and if it meets the criteria of `minDate`, `maxDate`, `required`, and `unavailable`.

    `isInputValid` will tell you only if the underlying `input` is parseable into a month and a day -- this does not consider whether the date is good according the other props.

    `isInputEmpty` will tell you if the underlying `input` has no digits entered.

    <LiveCode showCode example="datefieldyearless-isvalid" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import {
        DateFieldYearless,
        Flex,
        type YearlessDate,
        type DateFieldYearlessChange,
      } from "@servicetitan/anvil2";
      import { useState } from "react";

      function App() {
        const [value, setValue] = useState<YearlessDate | null>();
        const [latestEvent, setLatestEvent] = useState<DateFieldYearlessChange>();
        const [errorMessage, setErrorMessage] = useState("");

        const handleChange = (change: DateFieldYearlessChange) => {
          setValue(change.value);
          setLatestEvent(change);
          if (change.isValid) setErrorMessage("");
        };

        const handleBlur = () => {
          if (!latestEvent) return;
          if (!latestEvent.isValid) return setErrorMessage("Invalid date");
          if (!latestEvent.isInputValid && !latestEvent.isInputEmpty)
            return setErrorMessage("Valid date, but input isn't fully filled");
        };
        return (
          <Flex direction="column">
            <DateFieldYearless
              label="Yearless validation example"
              description="Will error on New Year's day and leap day"
              value={value}
              onChange={handleChange}
              onBlur={handleBlur}
              error={errorMessage}
              unavailable={{
                dates: [
                  { month: 1, day: 1 },
                  { month: 2, day: 29 },
                ],
              }}
            />
            <pre>{JSON.stringify(latestEvent, null, 2)}</pre>
          </Flex>
        );
      }

      export default App;
      ```
    </LiveCode>

    ### Disabled hint text

    The hint text can be disabled. If the hint text is disabled, ensure that the date format is displayed on the page.

    <LiveCode showCode example="datefieldyearless-disablehint" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { DateFieldYearless } from "@servicetitan/anvil2";

      function App() {
        return <DateFieldYearless disableHint />;
      }

      export default App;
      ```
    </LiveCode>

    ### Markdown in labels

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

    <LiveCode showCode example="datefieldyearless-markdownlabel" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { DateFieldYearless, Flex } from "@servicetitan/anvil2";

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

      export default App;
      ```
    </LiveCode>

    ### Hide the label

    Use `hideLabel` to visually hide the label. The `label` string is converted to an `aria-label` on the input so it remains accessible to screen readers — any inline markdown is stripped to plain text.

    <LiveCode showCode example="datefieldyearless-hidelabel" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { DateFieldYearless } from "@servicetitan/anvil2";

      function App() {
        return <DateFieldYearless label="Birthday" hideLabel />;
      }

      export default App;
      ```
    </LiveCode>
  </Tab>

  <Tab title="DateFieldYearless Props">
    ```tsx theme={null}
    import { DateFieldYearless } from "@servicetitan/anvil2";

    function ExampleComponent() {
    return (

    <DateFieldYearless
      defaultValue={{ month: 3, day: 22 }}
      mode="mm/dd"
      disableHint={false}
      required={false}
    />
    ); }

    ```

    ## `DateFieldYearless` Props

    <ParamField path="defaultValue" type={`"YearlessDate" | "null"`}>
      Uncontrolled initial value for the yearless date.
    </ParamField>

    <ParamField path="onChange" type="(change: DateFieldYearlessChange) => void">
      Callback fired when the value changes.
    </ParamField>

    <ParamField path="value" type={`"YearlessDate" | "null"`}>
      Controlled value for the yearless date.
    </ParamField>

    <ParamField path="disableHint" type="boolean" default="false">
      If true, disables the format hint below the field.
    </ParamField>

    <ParamField path="maxDate" type={`"YearlessDate" | "null"`}>
      Maximum selectable yearless date.
    </ParamField>

    <ParamField path="minDate" type={`"YearlessDate" | "null"`}>
      Minimum selectable yearless date.
    </ParamField>

    <ParamField path="mode" type={`"mm/dd" | "dd/mm"`} default="mm/dd">
      Date input format (yearless).
    </ParamField>

    <ParamField path="required" type="boolean" default="false">
      If true, the field is required.
    </ParamField>

    <ParamField path="unavailable" type="{ dates?: YearlessDate[] }">
      Yearless dates that are unavailable for selection.
    </ParamField>

    ### Additional field props

    The `DateFieldYearless` also support the following props which are common to most field components:

    <ParamField path="description" type="string">
      Additional description below the field.
    </ParamField>

    <ParamField path="disabled" type="boolean" default="false">
      If true, disables the field.
    </ParamField>

    <ParamField path="error" type="ReactElement | string | boolean">
      Error message or state.
    </ParamField>

    <ParamField path="errorAriaLive" type={`"off" | "polite" | "assertive"`} default="assertive">
      ARIA live region setting for error messages.
    </ParamField>

    <ParamField path="hideLabel" type="boolean" default="false">
      Visually hides the label while keeping it accessible to screen readers via `aria-label`.
    </ParamField>

    <ParamField path="label" type="ReactNode">
      Label for the field. Supports inline markdown formatting.

      <Warning>Omitting `label` is deprecated and will be required in v4.0.0. Use `hideLabel` to visually hide it. Passing `ReactNode` is also deprecated — use a plain string with inline markdown instead.</Warning>
    </ParamField>

    <ParamField path="labelProps" type="FieldLabelProps">
      Additional props passed to the [FieldLabel](/docs/web/components/field-label/code) component. Supports the `aiMark` prop for displaying [AI-powered field indicators](/docs/web/utilities/ai-marks).
    </ParamField>

    <ParamField path="loading" type="boolean" default="false">
      If true, shows a loading spinner.
    </ParamField>

    <ParamField path="moreInfo" type="ReactNode">
      Additional info icon or content for the label.
    </ParamField>

    <ParamField path="placeholder" type="string">
      Placeholder text.
    </ParamField>

    <ParamField path="size" type={`"small" | "medium" | "large"`} default="medium">
      Input size.
    </ParamField>

    <ParamField path="suffix" type="string | ReactElement">
      Suffix element to display inside the input.
    </ParamField>

    <ParamField path="type" type={`"text" | "email" | "tel" | "url" | "password" | "number"`} default="text">
      Input type.
    </ParamField>
  </Tab>

  <Tab title="DateFieldYearlessChange">
    ## DateFieldYearlessChange

    The `onChange` callback receives a DateFieldYearlessChange object with the following properties:

    <ParamField path="isInputEmpty" type="boolean">
      Whether the input is empty.
    </ParamField>

    <ParamField path="isInputValid" type="boolean">
      Whether the input matches the format and is not empty.
    </ParamField>

    <ParamField path="isValid" type="boolean">
      Whether the year-less date is valid according to all constraints (required,
      unavailable dates, min/max date, etc.).
    </ParamField>

    <ParamField path="value" type="string | null">
      The year-less date as an object with keys day and month.
    </ParamField>
  </Tab>
</Tabs>
