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

> Field for choosing a single 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="datefieldsingle-playground" fullWidth screenshot>
      ```tsx lines expandable theme={null}
      import { DateFieldSingle } from "@servicetitan/anvil2";

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

      export default App;
      ```
    </LiveCode>

    ## Common Examples

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

    function ExampleComponent() {
      return <DateFieldSingle defaultValue={new Date().toISOString()} />;
    }
    ```

    ### Default values

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

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

      function App() {
        return <DateFieldSingle defaultValue={new Date().toISOString()} />;
      }

      export default App;
      ```
    </LiveCode>

    ### Controlled usage

    The `DateFieldSingle` 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="datefieldsingle-controlled" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { DateFieldSingle, Flex, Button } from "@servicetitan/anvil2";
      import { useState } from "react";

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

        return (
          <Flex gap={4}>
            <DateFieldSingle
              value={value}
              onChange={(change) => setValue(change.date)}
            />
            <Button
              onClick={() => {
                setValue(new Date().toISOString());
              }}
            >
              Set to today
            </Button>
          </Flex>
        );
      }

      export default App;
      ```
    </LiveCode>

    ### Validation

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

    `isDateValid` will tell you if the *last entered date* is valid according to the props you've supplied (e.g. `required`, `minDate`, `maxDate`, and `unavailable`).

    `isInputValid` will tell you only if the underlying `input` is a parseable date -- 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.

    Typically, you will want to use these values together to determine the overall validity of the field. Though the simplest implementation may likely suffice to use only `isDateValid`.

    <LiveCode showCode example="datefieldsingle-isdatevalid" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import {
        DateFieldSingle,
        Flex,
        type DateFieldSingleChange,
      } from "@servicetitan/anvil2";
      import { useState } from "react";

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

        const handleChange = (change: DateFieldSingleChange) => {
          setValue(change.date);
          setLatestEvent(change);
          if (change.isDateValid) setErrorMessage("");
        };

        const handleBlur = () => {
          if (!latestEvent) return;
          if (!latestEvent.isDateValid) return setErrorMessage("Invalid date");
          if (!latestEvent.isInputValid && !latestEvent.isInputEmpty)
            return setErrorMessage("Valid date, but input isn't fully filled");
        };
        return (
          <Flex direction="column">
            <DateFieldSingle
              label="Weekdays Only"
              description="Type a date falling on a weekend to see an error"
              value={value}
              onChange={handleChange}
              onBlur={handleBlur}
              error={errorMessage}
              unavailable={{ daysOfWeek: [6, 7] }}
            />
            <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="datefieldsingle-disablehint" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { DateFieldSingle } from "@servicetitan/anvil2";

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

      export default App;
      ```
    </LiveCode>

    ### Timezone

    The `timezone` prop controls the meaning of the "Today" button and which month-year the calendar initially displays. When the timezone differs from the user's locale, a disambiguation message appears below the calendar.

    <LiveCode showCode example="datefieldsingle-timezone" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { DateFieldSingle } from "@servicetitan/anvil2";
      import { useState } from "react";

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

        return (
          <DateFieldSingle
            label="Appointment Date"
            timezone="Australia/Sydney"
            value={value}
            onChange={(change) => setValue(change.date)}
          />
        );
      }

      export default App;
      ```
    </LiveCode>

    ### Disable calendar popover

    The display of the `Calendar` can be prevented by passing `disableCalendar`.

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

      function App() {
        return <DateFieldSingle disableCalendar />;
      }

      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="datefieldsingle-markdownlabel" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { DateFieldSingle, Flex } from "@servicetitan/anvil2";

      function App() {
        return (
          <Flex direction="column" gap="4" style={{ maxWidth: 400 }}>
            <DateFieldSingle label="**Bold** label" />
            <DateFieldSingle label="*Italic* label" />
            <DateFieldSingle label="***Bold and italic*** label" />
            <DateFieldSingle label="==Highlight== label" />
            <DateFieldSingle 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="datefieldsingle-hidelabel" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { DateFieldSingle } from "@servicetitan/anvil2";

      function App() {
        return <DateFieldSingle label="Start date" hideLabel />;
      }

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

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

    function ExampleComponent() {
    return (

    <DateFieldSingle
      defaultValue={new Date().toISOString()}
      mode="mm/dd/yyyy"
      disableHint={false}
      disableCalendar={false}
      required={false}
    />
    ); }

    ```

    ## `DateFieldSingle` Props

    <ParamField path="defaultValue" type="string | null">
      Uncontrolled initial value for the date range.
    </ParamField>

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

    <ParamField path="value" type="string | null">
      Controlled value for the date range (ISO 8601 strings).
    </ParamField>

    <ParamField path="disableCalendar" type="boolean" default="false">
      If true, disables the calendar popover.
    </ParamField>

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

    <ParamField path="maxDate" type="string">
      Maximum selectable date (ISO 8601).
    </ParamField>

    <ParamField path="minDate" type="string">
      Minimum selectable date (ISO 8601).
    </ParamField>

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

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

    <ParamField path="timezone" type="IanaZone">
      IANA timezone identifier (e.g., "America/Los\_Angeles"). Controls the "Today" button behavior and initial calendar display. Shows a disambiguation message when different from the user's locale timezone.
    </ParamField>

    <ParamField path="unavailable" type="{ dates?: string[]; daysOfWeek?: (1 | 2 | 3 | 4 | 5 | 6 | 7)[] }">
      Dates or days of week that are unavailable for selection.
    </ParamField>

    ### Additional field props

    <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={`Omit<FieldLabelProps, "children" | "id" | "htmlFor">`}>
      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="DateFieldSingleChange">
    ## DateFieldSingleChange

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

    <ParamField path="date" type="string | null">
      The date in ISO 8601 format (e.g., "2025-07-02").
    </ParamField>

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

    <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>
  </Tab>
</Tabs>
