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

# Time Picker

> Time pickers help users enter or select a time of day as hours, minutes, and seconds, with locale-aware formatting and fewer entry errors.

export const CodeLivePreview = ({code, children, height, removePadding = false, mode = 'shadow'}) => {
  const previewRef = useRef(null);
  const BEEQ_VERSION = '1.16.2';
  const BEEQ_ESM_URL = `https://cdn.jsdelivr.net/npm/@beeq/core@${BEEQ_VERSION}/dist/beeq/beeq.esm.min.js`;
  const BEEQ_CSS_URL = `https://cdn.jsdelivr.net/npm/@beeq/core@${BEEQ_VERSION}/dist/beeq/beeq.css`;
  const BEEQ_ICONS_URL = `https://cdn.jsdelivr.net/npm/@beeq/core@${BEEQ_VERSION}/dist/beeq/svg`;
  const ensureParentBeeqRuntime = () => {
    if (document.querySelector('script[data-beeq-parent-runtime]')) return;
    const script = document.createElement('script');
    script.type = 'module';
    script.src = BEEQ_ESM_URL;
    script.dataset.beeqParentRuntime = BEEQ_ICONS_URL;
    document.head.appendChild(script);
  };
  const executeSnippetScripts = (root, runtimeWindow, previewRootArg, skipAttr) => {
    root.querySelectorAll('script').forEach(oldScript => {
      if (skipAttr && oldScript.hasAttribute(skipAttr)) return;
      if (oldScript.src) {
        const newScript = runtimeWindow.document.createElement('script');
        newScript.src = oldScript.src;
        oldScript.replaceWith(newScript);
        return;
      }
      runtimeWindow.Function('previewRoot', oldScript.textContent || '')(previewRootArg);
      oldScript.remove();
    });
  };
  const syncIframeMode = iframeDoc => {
    const root = document.documentElement;
    const explicitMode = root.getAttribute('bq-mode');
    const isDark = root.classList.contains('dark');
    const resolvedMode = explicitMode || (isDark ? 'dark' : 'light');
    iframeDoc.documentElement.setAttribute('bq-mode', resolvedMode);
    iframeDoc.body.setAttribute('bq-mode', resolvedMode);
  };
  useEffect(() => {
    if (mode === 'shadow') ensureParentBeeqRuntime();
  }, [mode]);
  useEffect(() => {
    const container = previewRef.current;
    if (!container) return;
    if (removePadding) container.style.padding = '0';
    container.innerHTML = '';
    if (mode === 'iframe') {
      const iframe = document.createElement('iframe');
      iframe.className = 'preview-iframe';
      iframe.style.width = '100%';
      iframe.style.border = '0';
      iframe.style.display = 'block';
      iframe.style.height = height ?? '';
      iframe.setAttribute('title', 'Live code preview');
      iframe.setAttribute('loading', 'lazy');
      iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
      container.appendChild(iframe);
      const iframeDoc = iframe.contentDocument;
      const iframeWin = iframe.contentWindow;
      if (!iframeDoc || !iframeWin) return;
      iframeDoc.open();
      iframeDoc.write(['<!doctype html>', '<html>', '<head>', '  <meta charset="utf-8" />', '  <meta name="viewport" content="width=device-width, initial-scale=1" />', '  <style>html,body{margin:0;padding:0;min-height:100%;}</style>', `  <link rel="stylesheet" href="${BEEQ_CSS_URL}" />`, `  <script type="module" src="${BEEQ_ESM_URL}" data-beeq-iframe-runtime="${BEEQ_ICONS_URL}"></script>`, '</head>', '<body>', code, '</body>', '</html>'].join('\n'));
      iframeDoc.close();
      syncIframeMode(iframeDoc);
      const modeObserver = new MutationObserver(() => syncIframeMode(iframeDoc));
      modeObserver.observe(document.documentElement, {
        attributes: true,
        attributeFilter: ['class', 'bq-mode']
      });
      executeSnippetScripts(iframeDoc, iframeWin, iframeDoc, 'data-beeq-iframe-runtime');
      return () => modeObserver.disconnect();
    }
    const shadowRoot = container.shadowRoot ?? container.attachShadow({
      mode: 'open'
    });
    if (!shadowRoot.adoptedStyleSheets.length) {
      const fixSheet = new CSSStyleSheet();
      fixSheet.replaceSync(`
        bq-dropdown::part(panel),
        bq-panel::part(panel),
        bq-select::part(panel),
        bq-date-picker::part(panel),
        bq-time-picker::part(panel) { z-index: 9999; }
        bq-tooltip::part(panel) { position: absolute; }
      `);
      shadowRoot.adoptedStyleSheets = [fixSheet];
    }
    shadowRoot.innerHTML = [`<link rel="stylesheet" href="${BEEQ_CSS_URL}">`, code].join('');
    executeSnippetScripts(shadowRoot, window, shadowRoot);
    return undefined;
  }, [code, mode, height]);
  return <div className="code-live-preview not-prose">
      {}
      <div className="preview" ref={previewRef} style={{
    minHeight: height
  }} />

      {}
      {children && <div className="code">{children}</div>}
    </div>;
};

export const CardTile = ({title, href, imageLightSrc, imageDarkSrc, children, enableImgZoom}) => {
  if (!href) {
    return <div className="card-tile block font-normal group relative my-2 ring-2 ring-transparent rounded-2xl overflow-hidden w-full">
        {imageLightSrc && <img className="w-full m-0 block dark:hidden" src={imageLightSrc} alt={title} {...enableImgZoom ? {
      zoom: true
    } : {
      noZoom: true
    }} />}
        {imageDarkSrc && <img className="w-full m-0 hidden dark:block" src={imageDarkSrc} alt={title} {...enableImgZoom ? {
      zoom: true
    } : {
      noZoom: true
    }} />}
        {title && <h2 className="mt-4 mb-2 px-6 text-base font-semibold">{title}</h2>}
        <div className="px-6 pb-5">{children}</div>
      </div>;
  }
  return <a href={href} className="card-tile block font-normal group relative my-2 ring-2 ring-transparent rounded-2xl overflow-hidden w-full cursor-pointer">
      {imageLightSrc && <img className="w-full m-0 block dark:hidden" src={imageLightSrc} alt={title} noZoom />}
      {imageDarkSrc && <img className="w-full m-0 hidden dark:block" src={imageDarkSrc} alt={title} noZoom />}
      {title && <h2 className="mt-4 mb-2 px-6 text-base font-semibold">{title}</h2>}
      <div className="px-6 pb-5">{children}</div>
    </a>;
};

<Frame className="px-4 py-4" caption="Time-picker component overview">
  <img className="block dark:hidden" src="https://mintcdn.com/beeq/zFWLD2Ond2vY12Ly/components/images/time-picker/time-picker-overview-light.svg?fit=max&auto=format&n=zFWLD2Ond2vY12Ly&q=85&s=b1b9b5d7c948d3c23b38b73b5e932be0" alt="BEEQ Time-picker component overview" width="328" height="451" data-path="components/images/time-picker/time-picker-overview-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/beeq/zFWLD2Ond2vY12Ly/components/images/time-picker/time-picker-overview-dark.svg?fit=max&auto=format&n=zFWLD2Ond2vY12Ly&q=85&s=f9e6d3d6141cbee730e66d9e9370c6ff" alt="BEEQ Time-picker component overview" width="328" height="451" data-path="components/images/time-picker/time-picker-overview-dark.svg" />
</Frame>

Time pickers combine locale-ordered hour, minute, and second segments with a panel of scrollable columns. People can type a time directly or pick it from the panel, and the component keeps the value in a predictable 24-hour format.

<Note>
  Use a time picker when people need to set a time of day. To pick a date and a time together, pair it with a [date picker](/components/date-picker). For a short list of fixed slots, such as three delivery windows, a [select](/components/select) or radio group is clearer.
</Note>

## When to use

<CardGroup cols={2}>
  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="thumbs-up" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Use time pickers when
    </span>

    * People need to set a specific time of day, such as a meeting start or an alarm
    * The time must follow local conventions, like segment order and AM/PM labels
    * You need to limit times with business hours or fixed intervals
    * Typing and picking should both be quick and error-free
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="thumbs-down" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Do not use time pickers when
    </span>

    * Only a handful of fixed time slots are available
    * People need to enter a duration longer than a day
    * The value is a relative time, like "in 2 hours"
    * An approximate time of day, like "morning", is enough
  </Card>
</CardGroup>

## Patterns

<CardGroup cols={2}>
  <CardTile title="Instant selection">
    Each pick in the panel updates the value right away. Use it for most forms, where a time is easy to change later.
  </CardTile>

  <CardTile title="Confirmed selection">
    With `require-confirm`, panel picks stay a draft in the panel, and the field keeps the current time until people press OK or `Enter`. Use it when a new time triggers a costly change, such as rescheduling a booking.
  </CardTile>
</CardGroup>

## Anatomy

<Frame className="px-4 py-4" caption="Time-picker component anatomy">
  <img className="block dark:hidden" src="https://mintcdn.com/beeq/zFWLD2Ond2vY12Ly/components/images/time-picker/time-picker-anatomy-light.svg?fit=max&auto=format&n=zFWLD2Ond2vY12Ly&q=85&s=35f780c63be60958a0625471555c8ad1" alt="BEEQ Time-picker component anatomy" width="416" height="449" data-path="components/images/time-picker/time-picker-anatomy-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/beeq/zFWLD2Ond2vY12Ly/components/images/time-picker/time-picker-anatomy-dark.svg?fit=max&auto=format&n=zFWLD2Ond2vY12Ly&q=85&s=363b79150677d72d97a048605066bdcd" alt="BEEQ Time-picker component anatomy" width="416" height="449" data-path="components/images/time-picker/time-picker-anatomy-dark.svg" />
</Frame>

The time picker pairs a labeled, segmented field with a panel of columns, one per time unit. The example uses `second` precision, a 12-hour clock, and a prefix icon to show every part. Keep the label specific and let the locale decide the segment order and labels.

| Part | Element | Description |
| - | - | - |
| **1** | Label | Describes which time the field asks for (`label` slot) |
| **2** | Prefix | Optional icon or text before the time segments (`prefix` slot) |
| **3** | Time segments | The hour, minute, second, and AM/PM controls people focus and edit, ordered for the active locale |
| **4** | Clear button | Removes the current value; hidden with `disable-clear` |
| **5** | Clock trigger | Opens the panel; its icon can be replaced with the `suffix` slot |
| **6** | Panel | The surface that holds the columns and the footer actions |
| **7** | Column | A scrollable list of options for one time unit, under a header that names it and stays in place while the list scrolls |
| **8** | Selected option | The current hour, minute, second, or period, shown with selected styling |
| **9** | Now button | Picks the current time, rounded down to the step; hidden with `disable-now` |
| **10** | OK button | Confirms the selection and closes the panel |

## Design guidelines

<Steps>
  <Step title="Pick the right precision">
    Start with the default `minute` precision. Use `hour` for coarse slots, such as opening hours, and `second` only when seconds matter, such as lap times or logs.
  </Step>

  <Step title="Let the locale drive the format">
    Set `locale` to the product locale, so segment order, separators, and AM/PM labels match what people expect. The clock is 24-hour by default; set `hour-format="12"` when people expect a 12-hour clock.
  </Step>

  <Step title="Constrain the choices">
    Apply `min`, `max`, and step values when business rules are known. Options outside the rules are disabled in the panel, and typed values are clamped when focus leaves the field.
  </Step>
</Steps>

<Note>
  Use steps that divide evenly into the unit, such as 5, 10, 15, or 30 minutes, so the options stay predictable and easy to scan.
</Note>

<Tip>
  Keep the clock trigger visible. It signals that a panel is available and gives pointer users a faster way to pick a time.
</Tip>

## Usage

### Default

Use the default configuration when people need to set an hour and minute. Click the field or the clock icon to open the panel, or type the time directly.

<Note>
  The `value` attribute, `min`, and `max` always use a 24-hour wire format, whatever the display: `HH:mm` at minute precision, `HH:00` at hour precision, and `HH:mm:ss` at second precision.

  A locale-derived format hint, such as `hh:mm`, shows the expected layout before entry starts. On focus, one segment is active. Type digits to replace that segment, use `ArrowLeft` and `ArrowRight` to move, `Home` and `End` to reach the first or last segment, `ArrowUp` and `ArrowDown` to change a value, and `Backspace` or `Delete` to clear a segment. For AM/PM, type `A` or `P`. Paste is not supported.
</Note>

<CodeLivePreview
  mode="shadow"
  code={`
<bq-time-picker name="meeting-time">
<label slot="label">Meeting time</label>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker name="meeting-time">
      <label slot="label">Meeting time</label>
    </bq-time-picker>
    ```

    ```jsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqTimePicker } from "@beeq/react";

    <BqTimePicker name="meeting-time">
      <label slot="label">Meeting time</label>
    </BqTimePicker>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqTimePicker],
      template: `
        <bq-time-picker name="meeting-time">
          <label slot="label">Meeting time</label>
        </bq-time-picker>
      `
    })
    export class DefaultTimePickerComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqTimePicker } from "@beeq/vue";
    </script>

    <template>
      <BqTimePicker name="meeting-time">
        <label slot="label">Meeting time</label>
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

## Options

### Precision

Use `precision` to choose the smallest unit people edit and submit. The field and the panel only show the matching segments and columns. At hour precision on a 24-hour clock, the panel adds a disabled minute column fixed at `00`, so it reads as a time.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  justify-content: flex-start !important;
  position: relative;
  width: 100%;
  z-index: 11;
}
</style>

<bq-time-picker name="opening-hour" precision="hour" value="09:00">
<label slot="label">Opening hour</label>
</bq-time-picker>

<bq-time-picker name="start-time" value="09:30">
<label slot="label">Start time</label>
</bq-time-picker>

<bq-time-picker name="lap-time" precision="second" value="09:30:15">
<label slot="label">Lap time</label>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker name="opening-hour" precision="hour" value="09:00">
      <label slot="label">Opening hour</label>
    </bq-time-picker>

    <bq-time-picker name="start-time" value="09:30">
      <label slot="label">Start time</label>
    </bq-time-picker>

    <bq-time-picker name="lap-time" precision="second" value="09:30:15">
      <label slot="label">Lap time</label>
    </bq-time-picker>
    ```

    ```jsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqTimePicker } from "@beeq/react";

    <>
      <BqTimePicker name="opening-hour" precision="hour" value="09:00">
        <label slot="label">Opening hour</label>
      </BqTimePicker>

      <BqTimePicker name="start-time" value="09:30">
        <label slot="label">Start time</label>
      </BqTimePicker>

      <BqTimePicker name="lap-time" precision="second" value="09:30:15">
        <label slot="label">Lap time</label>
      </BqTimePicker>
    </>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqTimePicker],
      template: `
        <bq-time-picker name="opening-hour" precision="hour" value="09:00">
          <label slot="label">Opening hour</label>
        </bq-time-picker>

        <bq-time-picker name="start-time" value="09:30">
          <label slot="label">Start time</label>
        </bq-time-picker>

        <bq-time-picker name="lap-time" precision="second" value="09:30:15">
          <label slot="label">Lap time</label>
        </bq-time-picker>
      `
    })
    export class TimePickerPrecisionComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqTimePicker } from "@beeq/vue";
    </script>

    <template>
      <BqTimePicker name="opening-hour" precision="hour" value="09:00">
        <label slot="label">Opening hour</label>
      </BqTimePicker>

      <BqTimePicker name="start-time" value="09:30">
        <label slot="label">Start time</label>
      </BqTimePicker>

      <BqTimePicker name="lap-time" precision="second" value="09:30:15">
        <label slot="label">Lap time</label>
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### 12-hour and 24-hour clock

The clock is 24-hour by default, whatever the `locale`. Set `hour-format="12"` for a 12-hour clock with an AM/PM segment. The submitted `value` stays in 24-hour format.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  justify-content: flex-start !important;
  position: relative;
  width: 100%;
  z-index: 11;
}
</style>

<bq-time-picker hour-format="12" name="alarm-12h" value="14:30">
<label slot="label">12-hour clock</label>
</bq-time-picker>

<bq-time-picker name="alarm-24h" value="14:30">
<label slot="label">24-hour clock</label>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker hour-format="12" name="alarm-12h" value="14:30">
      <label slot="label">12-hour clock</label>
    </bq-time-picker>

    <bq-time-picker name="alarm-24h" value="14:30">
      <label slot="label">24-hour clock</label>
    </bq-time-picker>
    ```

    ```jsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqTimePicker } from "@beeq/react";

    <>
      <BqTimePicker hourFormat="12" name="alarm-12h" value="14:30">
        <label slot="label">12-hour clock</label>
      </BqTimePicker>

      <BqTimePicker name="alarm-24h" value="14:30">
        <label slot="label">24-hour clock</label>
      </BqTimePicker>
    </>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqTimePicker],
      template: `
        <bq-time-picker hour-format="12" name="alarm-12h" value="14:30">
          <label slot="label">12-hour clock</label>
        </bq-time-picker>

        <bq-time-picker name="alarm-24h" value="14:30">
          <label slot="label">24-hour clock</label>
        </bq-time-picker>
      `
    })
    export class TimePickerHourFormatComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqTimePicker } from "@beeq/vue";
    </script>

    <template>
      <BqTimePicker hourFormat="12" name="alarm-12h" value="14:30">
        <label slot="label">12-hour clock</label>
      </BqTimePicker>

      <BqTimePicker name="alarm-24h" value="14:30">
        <label slot="label">24-hour clock</label>
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Locale

Use `locale` to set the segment order, separators, AM/PM labels, and column headers. Some locales place the period before the hour, and the panel columns follow the same order. The examples set `hour-format="12"` where the locale usually shows a 12-hour clock.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  justify-content: flex-start !important;
  position: relative;
  width: 100%;
  z-index: 11;
}
</style>

<bq-time-picker hour-format="12" locale="en-US" name="time-us" value="14:30">
<label slot="label">English (US)</label>
</bq-time-picker>

<bq-time-picker locale="de-DE" name="time-de" value="14:30">
<label slot="label">Deutsch</label>
</bq-time-picker>

<bq-time-picker hour-format="12" locale="ko-KR" name="time-ko" value="14:30">
<label slot="label">한국어</label>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker hour-format="12" locale="en-US" name="time-us" value="14:30">
      <label slot="label">English (US)</label>
    </bq-time-picker>

    <bq-time-picker locale="de-DE" name="time-de" value="14:30">
      <label slot="label">Deutsch</label>
    </bq-time-picker>

    <bq-time-picker hour-format="12" locale="ko-KR" name="time-ko" value="14:30">
      <label slot="label">한국어</label>
    </bq-time-picker>
    ```

    ```jsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqTimePicker } from "@beeq/react";

    <>
      <BqTimePicker hourFormat="12" locale="en-US" name="time-us" value="14:30">
        <label slot="label">English (US)</label>
      </BqTimePicker>

      <BqTimePicker locale="de-DE" name="time-de" value="14:30">
        <label slot="label">Deutsch</label>
      </BqTimePicker>

      <BqTimePicker hourFormat="12" locale="ko-KR" name="time-ko" value="14:30">
        <label slot="label">한국어</label>
      </BqTimePicker>
    </>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqTimePicker],
      template: `
        <bq-time-picker hour-format="12" locale="en-US" name="time-us" value="14:30">
          <label slot="label">English (US)</label>
        </bq-time-picker>

        <bq-time-picker locale="de-DE" name="time-de" value="14:30">
          <label slot="label">Deutsch</label>
        </bq-time-picker>

        <bq-time-picker hour-format="12" locale="ko-KR" name="time-ko" value="14:30">
          <label slot="label">한국어</label>
        </bq-time-picker>
      `
    })
    export class TimePickerLocaleComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqTimePicker } from "@beeq/vue";
    </script>

    <template>
      <BqTimePicker hourFormat="12" locale="en-US" name="time-us" value="14:30">
        <label slot="label">English (US)</label>
      </BqTimePicker>

      <BqTimePicker locale="de-DE" name="time-de" value="14:30">
        <label slot="label">Deutsch</label>
      </BqTimePicker>

      <BqTimePicker hourFormat="12" locale="ko-KR" name="time-ko" value="14:30">
        <label slot="label">한국어</label>
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Labels

Use `labels` to change the column headers, AM/PM labels, button text, and accessible names, for example to translate them. Pass an object, or a JSON string through the HTML attribute. Every key is optional: `hour`, `minute`, `second`, `am`, and `pm` default to the `locale` names, `period` defaults to the AM and PM labels joined by a slash, and the rest default to English.

| Key | Used for | Default |
| - | - | - |
| `hour` | Hour column header and hour segment name | Locale name, e.g. `hour` |
| `minute` | Minute column header and minute segment name | Locale name, e.g. `minute` |
| `second` | Second column header and second segment name | Locale name, e.g. `second` |
| `period` | AM/PM column header and AM/PM segment name | `am` and `pm` joined by a slash |
| `am` | Morning period in the field and the panel | Locale label, e.g. `am` |
| `pm` | Afternoon period in the field and the panel | Locale label, e.g. `pm` |
| `now` | "Now" button text | `"Now"` |
| `clear` | Clear button name | `"Clear"` |
| `confirm` | Confirm button text | `"OK"` |
| `openPanel` | Clock trigger button name | `"Open time picker"` |
| `panelLabel` | Panel name | `"Choose time"` |

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  justify-content: flex-start !important;
  position: relative;
  width: 100%;
  z-index: 11;
}
</style>

<bq-time-picker
hour-format="12"
labels='{"hour":"Heure","minute":"Minute","am":"matin","pm":"soir","period":"Moment","now":"Maintenant","clear":"Effacer","confirm":"Valider","openPanel":"Ouvrir le sélecteur d’heure","panelLabel":"Choisir l’heure"}'
locale="fr-FR"
name="rdv"
value="14:30"
>
<label slot="label">Heure du rendez-vous</label>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker
      hour-format="12"
      labels='{"hour":"Heure","minute":"Minute","am":"matin","pm":"soir","period":"Moment","now":"Maintenant","clear":"Effacer","confirm":"Valider","openPanel":"Ouvrir le sélecteur d’heure","panelLabel":"Choisir l’heure"}'
      locale="fr-FR"
      name="rdv"
      value="14:30"
    >
      <label slot="label">Heure du rendez-vous</label>
    </bq-time-picker>
    ```

    ```jsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqTimePicker } from "@beeq/react";

    const labels = {
      hour: "Heure",
      minute: "Minute",
      am: "matin",
      pm: "soir",
      period: "Moment",
      now: "Maintenant",
      clear: "Effacer",
      confirm: "Valider",
      openPanel: "Ouvrir le sélecteur d’heure",
      panelLabel: "Choisir l’heure",
    };

    <BqTimePicker hourFormat="12" labels={labels} locale="fr-FR" name="rdv" value="14:30">
      <label slot="label">Heure du rendez-vous</label>
    </BqTimePicker>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqTimePicker } from "@beeq/angular/standalone";
    import type { TTimePickerLabels } from "@beeq/core";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqTimePicker],
      template: `
        <bq-time-picker hour-format="12" [labels]="labels" locale="fr-FR" name="rdv" value="14:30">
          <label slot="label">Heure du rendez-vous</label>
        </bq-time-picker>
      `
    })
    export class TimePickerLabelsComponent {
      labels: TTimePickerLabels = {
        hour: "Heure",
        minute: "Minute",
        am: "matin",
        pm: "soir",
        period: "Moment",
        now: "Maintenant",
        clear: "Effacer",
        confirm: "Valider",
        openPanel: "Ouvrir le sélecteur d’heure",
        panelLabel: "Choisir l’heure",
      };
    }
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqTimePicker } from "@beeq/vue";

    const labels = {
      hour: "Heure",
      minute: "Minute",
      am: "matin",
      pm: "soir",
      period: "Moment",
      now: "Maintenant",
      clear: "Effacer",
      confirm: "Valider",
      openPanel: "Ouvrir le sélecteur d’heure",
      panelLabel: "Choisir l’heure",
    };
    </script>

    <template>
      <BqTimePicker hourFormat="12" :labels="labels" locale="fr-FR" name="rdv" value="14:30">
        <label slot="label">Heure du rendez-vous</label>
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Minimum and maximum time

Use `min` and `max` to set the earliest and latest selectable times. Options outside the range are disabled in the panel, and the "Now" button is disabled when the current time is out of range. If `min` is later than `max`, both are ignored.

<CodeLivePreview
  mode="shadow"
  code={`
<bq-time-picker max="17:30" min="09:00" name="office-hours" value="10:00">
<label slot="label">Office hours</label>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker max="17:30" min="09:00" name="office-hours" value="10:00">
      <label slot="label">Office hours</label>
    </bq-time-picker>
    ```

    ```jsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqTimePicker } from "@beeq/react";

    <BqTimePicker max="17:30" min="09:00" name="office-hours" value="10:00">
      <label slot="label">Office hours</label>
    </BqTimePicker>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqTimePicker],
      template: `
        <bq-time-picker max="17:30" min="09:00" name="office-hours" value="10:00">
          <label slot="label">Office hours</label>
        </bq-time-picker>
      `
    })
    export class TimePickerMinMaxComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqTimePicker } from "@beeq/vue";
    </script>

    <template>
      <BqTimePicker max="17:30" min="09:00" name="office-hours" value="10:00">
        <label slot="label">Office hours</label>
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Steps

Use `hour-step`, `minute-step`, and `second-step` to show options at fixed intervals. Typed values that fall between steps are kept but flagged as invalid, and "Now" rounds down to the nearest step.

<CodeLivePreview
  mode="shadow"
  code={`
<bq-time-picker minute-step="15" name="slot-time" value="10:15">
<label slot="label">Appointment slot</label>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker minute-step="15" name="slot-time" value="10:15">
      <label slot="label">Appointment slot</label>
    </bq-time-picker>
    ```

    ```jsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqTimePicker } from "@beeq/react";

    <BqTimePicker minuteStep={15} name="slot-time" value="10:15">
      <label slot="label">Appointment slot</label>
    </BqTimePicker>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqTimePicker],
      template: `
        <bq-time-picker [minuteStep]="15" name="slot-time" value="10:15">
          <label slot="label">Appointment slot</label>
        </bq-time-picker>
      `
    })
    export class TimePickerStepsComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqTimePicker } from "@beeq/vue";
    </script>

    <template>
      <BqTimePicker :minuteStep="15" name="slot-time" value="10:15">
        <label slot="label">Appointment slot</label>
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Require confirmation

With `require-confirm`, panel picks, including "Now", stay a draft until people press OK or `Enter`. `Escape`, an outside click, or moving focus away discards the draft. Values typed in the field are always committed right away.

<CodeLivePreview
  mode="shadow"
  code={`
<bq-time-picker name="departure-time" require-confirm value="08:45">
<label slot="label">Departure time</label>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker name="departure-time" require-confirm value="08:45">
      <label slot="label">Departure time</label>
    </bq-time-picker>
    ```

    ```jsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqTimePicker } from "@beeq/react";

    <BqTimePicker name="departure-time" requireConfirm value="08:45">
      <label slot="label">Departure time</label>
    </BqTimePicker>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqTimePicker],
      template: `
        <bq-time-picker name="departure-time" require-confirm value="08:45">
          <label slot="label">Departure time</label>
        </bq-time-picker>
      `
    })
    export class TimePickerConfirmComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqTimePicker } from "@beeq/vue";
    </script>

    <template>
      <BqTimePicker name="departure-time" requireConfirm value="08:45">
        <label slot="label">Departure time</label>
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Without the Now button

Set `disable-now` to hide the "Now" button when the current time isn't a meaningful choice, such as for reminders set for later in the day. The OK button is always shown.

<CodeLivePreview
  mode="shadow"
  code={`
<bq-time-picker disable-now name="reminder-time" value="18:00">
<label slot="label">Reminder time</label>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker disable-now name="reminder-time" value="18:00">
      <label slot="label">Reminder time</label>
    </bq-time-picker>
    ```

    ```jsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqTimePicker } from "@beeq/react";

    <BqTimePicker disableNow name="reminder-time" value="18:00">
      <label slot="label">Reminder time</label>
    </BqTimePicker>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqTimePicker],
      template: `
        <bq-time-picker disable-now name="reminder-time" value="18:00">
          <label slot="label">Reminder time</label>
        </bq-time-picker>
      `
    })
    export class TimePickerWithoutNowComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqTimePicker } from "@beeq/vue";
    </script>

    <template>
      <BqTimePicker disableNow name="reminder-time" value="18:00">
        <label slot="label">Reminder time</label>
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Prefix and suffix

Use the `prefix` slot to add context before the value. The `suffix` slot replaces the clock icon inside the trigger button, so set `labels.openPanel` to keep the button name accurate.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  justify-content: flex-start !important;
  position: relative;
  width: 100%;
  z-index: 11;
}
</style>

<bq-time-picker name="wake-up" value="07:00">
<label slot="label">Wake-up alarm</label>
<bq-icon name="alarm" slot="prefix"></bq-icon>
</bq-time-picker>

<bq-time-picker labels='{"openPanel":"Choose end time"}' name="timer-end" value="07:20">
<label slot="label">Timer ends</label>
<bq-icon name="clock-countdown" slot="suffix"></bq-icon>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker name="wake-up" value="07:00">
      <label slot="label">Wake-up alarm</label>
      <bq-icon name="alarm" slot="prefix"></bq-icon>
    </bq-time-picker>

    <bq-time-picker labels='{"openPanel":"Choose end time"}' name="timer-end" value="07:20">
      <label slot="label">Timer ends</label>
      <bq-icon name="clock-countdown" slot="suffix"></bq-icon>
    </bq-time-picker>
    ```

    ```jsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqIcon, BqTimePicker } from "@beeq/react";

    <>
      <BqTimePicker name="wake-up" value="07:00">
        <label slot="label">Wake-up alarm</label>
        <BqIcon name="alarm" slot="prefix" />
      </BqTimePicker>

      <BqTimePicker labels={{ openPanel: "Choose end time" }} name="timer-end" value="07:20">
        <label slot="label">Timer ends</label>
        <BqIcon name="clock-countdown" slot="suffix" />
      </BqTimePicker>
    </>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqIcon, BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqIcon, BqTimePicker],
      template: `
        <bq-time-picker name="wake-up" value="07:00">
          <label slot="label">Wake-up alarm</label>
          <bq-icon name="alarm" slot="prefix"></bq-icon>
        </bq-time-picker>

        <bq-time-picker [labels]="{ openPanel: 'Choose end time' }" name="timer-end" value="07:20">
          <label slot="label">Timer ends</label>
          <bq-icon name="clock-countdown" slot="suffix"></bq-icon>
        </bq-time-picker>
      `
    })
    export class TimePickerPrefixSuffixComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqIcon, BqTimePicker } from "@beeq/vue";
    </script>

    <template>
      <BqTimePicker name="wake-up" value="07:00">
        <label slot="label">Wake-up alarm</label>
        <BqIcon name="alarm" slot="prefix" />
      </BqTimePicker>

      <BqTimePicker :labels="{ openPanel: 'Choose end time' }" name="timer-end" value="07:20">
        <label slot="label">Timer ends</label>
        <BqIcon name="clock-countdown" slot="suffix" />
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Without the clear button

Set `disable-clear` to hide the clear button when the field should always hold a value.

<CodeLivePreview
  mode="shadow"
  code={`
<bq-time-picker disable-clear name="check-in" value="15:00">
<label slot="label">Check-in time</label>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker disable-clear name="check-in" value="15:00">
      <label slot="label">Check-in time</label>
    </bq-time-picker>
    ```

    ```jsx React icon="react" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqTimePicker } from "@beeq/react";

    <BqTimePicker disableClear name="check-in" value="15:00">
      <label slot="label">Check-in time</label>
    </BqTimePicker>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqTimePicker],
      template: `
        <bq-time-picker disable-clear name="check-in" value="15:00">
          <label slot="label">Check-in time</label>
        </bq-time-picker>
      `
    })
    export class TimePickerDisableClearComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqTimePicker } from "@beeq/vue";
    </script>

    <template>
      <BqTimePicker disableClear name="check-in" value="15:00">
        <label slot="label">Check-in time</label>
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Disabled and read-only

Use `disabled` when the time isn't available for editing and shouldn't be submitted. Use `readonly` when people should see and submit the value but not change it: the segments stay focusable, and the panel doesn't open.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  justify-content: flex-start !important;
  position: relative;
  width: 100%;
  z-index: 11;
}
</style>

<bq-time-picker disabled name="disabled-time" value="12:00">
<label slot="label">Disabled</label>
</bq-time-picker>

<bq-time-picker name="readonly-time" readonly value="12:00">
<label slot="label">Read-only</label>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker disabled name="disabled-time" value="12:00">
      <label slot="label">Disabled</label>
    </bq-time-picker>

    <bq-time-picker name="readonly-time" readonly value="12:00">
      <label slot="label">Read-only</label>
    </bq-time-picker>
    ```

    ```jsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqTimePicker } from "@beeq/react";

    <>
      <BqTimePicker disabled name="disabled-time" value="12:00">
        <label slot="label">Disabled</label>
      </BqTimePicker>

      <BqTimePicker name="readonly-time" readonly value="12:00">
        <label slot="label">Read-only</label>
      </BqTimePicker>
    </>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqTimePicker],
      template: `
        <bq-time-picker disabled name="disabled-time" value="12:00">
          <label slot="label">Disabled</label>
        </bq-time-picker>

        <bq-time-picker name="readonly-time" readonly value="12:00">
          <label slot="label">Read-only</label>
        </bq-time-picker>
      `
    })
    export class TimePickerStatesComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqTimePicker } from "@beeq/vue";
    </script>

    <template>
      <BqTimePicker disabled name="disabled-time" value="12:00">
        <label slot="label">Disabled</label>
      </BqTimePicker>

      <BqTimePicker name="readonly-time" readonly value="12:00">
        <label slot="label">Read-only</label>
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Validation states

Use `validation-status` when the field should show immediate visual feedback after validation.

<CodeLivePreview
  mode="shadow"
  code={`
<style>
:host {
  justify-content: flex-start !important;
  position: relative;
  width: 100%;
  z-index: 11;
}
</style>

<bq-time-picker name="time-error" validation-status="error" value="07:15">
<label slot="label">Error</label>
</bq-time-picker>

<bq-time-picker name="time-warning" validation-status="warning" value="07:15">
<label slot="label">Warning</label>
</bq-time-picker>

<bq-time-picker name="time-success" validation-status="success" value="07:15">
<label slot="label">Success</label>
</bq-time-picker>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <bq-time-picker name="time-error" validation-status="error" value="07:15">
      <label slot="label">Error</label>
    </bq-time-picker>

    <bq-time-picker name="time-warning" validation-status="warning" value="07:15">
      <label slot="label">Warning</label>
    </bq-time-picker>

    <bq-time-picker name="time-success" validation-status="success" value="07:15">
      <label slot="label">Success</label>
    </bq-time-picker>
    ```

    ```jsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { BqTimePicker } from "@beeq/react";

    <>
      <BqTimePicker name="time-error" validationStatus="error" value="07:15">
        <label slot="label">Error</label>
      </BqTimePicker>

      <BqTimePicker name="time-warning" validationStatus="warning" value="07:15">
        <label slot="label">Warning</label>
      </BqTimePicker>

      <BqTimePicker name="time-success" validationStatus="success" value="07:15">
        <label slot="label">Success</label>
      </BqTimePicker>
    </>
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqTimePicker],
      template: `
        <bq-time-picker name="time-error" validation-status="error" value="07:15">
          <label slot="label">Error</label>
        </bq-time-picker>

        <bq-time-picker name="time-warning" validation-status="warning" value="07:15">
          <label slot="label">Warning</label>
        </bq-time-picker>

        <bq-time-picker name="time-success" validation-status="success" value="07:15">
          <label slot="label">Success</label>
        </bq-time-picker>
      `
    })
    export class TimePickerValidationComponent {}
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { BqTimePicker } from "@beeq/vue";
    </script>

    <template>
      <BqTimePicker name="time-error" validationStatus="error" value="07:15">
        <label slot="label">Error</label>
      </BqTimePicker>

      <BqTimePicker name="time-warning" validationStatus="warning" value="07:15">
        <label slot="label">Warning</label>
      </BqTimePicker>

      <BqTimePicker name="time-success" validationStatus="success" value="07:15">
        <label slot="label">Success</label>
      </BqTimePicker>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

### Form integration

`bq-time-picker` submits its current value with the form, in 24-hour format. Use `required` and `form-validation-message` when the time is mandatory; the custom message also applies to incomplete, out-of-range, and off-step values.

<Warning>
  A partly filled field becomes invalid when focus leaves it, even when the picker is optional. The draft stays visible and the last committed `value` is preserved, but native form validation blocks submission until people complete the time, pick one from the panel, or clear the field.
</Warning>

When focus leaves the field, complete times outside `min` or `max` are clamped to the nearest bound. A disabled time picker is excluded from form data; a read-only one is still submitted.

<CodeLivePreview
  mode="iframe"
  height="30rem"
  removePadding
  code={`
<style>
body {
  padding: var(--bq-spacing-l);
}

.time-form {
  display: grid;
  gap: var(--bq-spacing-m);
}

.time-form__actions {
  display: flex;
  gap: var(--bq-spacing-s);
  justify-content: flex-end;
}

.time-form__output {
  margin: 0;
  padding: var(--bq-spacing-s);
  border: var(--bq-stroke-s) solid var(--bq-stroke--tertiary);
  border-radius: var(--bq-radius--s);
  background: var(--bq-ui--secondary);
  color: var(--bq-text--primary);
  white-space: pre-wrap;
}
</style>

<form class="time-form" id="time-form">
<bq-time-picker
  form-validation-message="Choose a start time"
  name="startTime"
  required
>
  <label slot="label">Start time</label>
</bq-time-picker>
<div class="time-form__actions">
  <bq-button appearance="secondary" type="reset">Reset</bq-button>
  <bq-button type="button">Submit</bq-button>
</div>
<pre class="time-form__output" id="time-output">{}</pre>
</form>

<script>
(() => {
  const form = previewRoot.querySelector('#time-form');
  const output = previewRoot.querySelector('#time-output');
  const submitButton = form.querySelector('bq-button[type="button"]');

  const showFormData = () => {
    if (!form.reportValidity()) return;
    output.textContent = JSON.stringify(Object.fromEntries(new FormData(form).entries()), null, 2);
  };

  submitButton?.addEventListener('bqClick', (event) => {
    event.preventDefault();
    showFormData();
  });

  form.addEventListener('submit', (event) => {
    event.preventDefault();
    showFormData();
  });

  form.addEventListener('reset', () => {
    requestAnimationFrame(() => {
      output.textContent = '{}';
    });
  });
})();
</script>
`}
>
  <CodeGroup>
    ```html HTML icon="html5" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <form id="time-form">
      <bq-time-picker
        form-validation-message="Choose a start time"
        name="startTime"
        required
      >
        <label slot="label">Start time</label>
      </bq-time-picker>
      <bq-button appearance="secondary" type="reset">Reset</bq-button>
      <bq-button type="submit">Submit</bq-button>
      <pre id="time-output">{}</pre>
    </form>

    <script>
      const form = document.querySelector('#time-form');
      const output = document.querySelector('#time-output');

      form.addEventListener('submit', (event) => {
        event.preventDefault();
        output.textContent = JSON.stringify(Object.fromEntries(new FormData(form).entries()), null, 2);
      });

      form.addEventListener('reset', () => {
        requestAnimationFrame(() => {
          output.textContent = '{}';
        });
      });
    </script>
    ```

    ```tsx React icon="react" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { useState } from "react";
    import { BqButton, BqTimePicker } from "@beeq/react";

    export default function TimePickerForm() {
      const [data, setData] = useState("{}");

      return (
        <form
          onReset={() => setData("{}")}
          onSubmit={(event) => {
            event.preventDefault();
            setData(JSON.stringify(Object.fromEntries(new FormData(event.currentTarget).entries()), null, 2));
          }}
        >
          <BqTimePicker
            formValidationMessage="Choose a start time"
            name="startTime"
            required
          >
            <label slot="label">Start time</label>
          </BqTimePicker>
          <BqButton appearance="secondary" type="reset">Reset</BqButton>
          <BqButton type="submit">Submit</BqButton>
          <pre>{data}</pre>
        </form>
      );
    }
    ```

    ```ts Angular icon="angular" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    import { Component } from "@angular/core";
    import { BqButton, BqTimePicker } from "@beeq/angular/standalone";

    @Component({
      selector: "app-root",
      standalone: true,
      imports: [BqButton, BqTimePicker],
      template: `
        <form (reset)="data = '{}'" (submit)="handleSubmit($event)">
          <bq-time-picker
            form-validation-message="Choose a start time"
            name="startTime"
            required
          >
            <label slot="label">Start time</label>
          </bq-time-picker>
          <bq-button appearance="secondary" type="reset">Reset</bq-button>
          <bq-button type="submit">Submit</bq-button>
          <pre>{{ data }}</pre>
        </form>
      `,
    })
    export class TimePickerFormComponent {
      data = "{}";

      handleSubmit(event: SubmitEvent): void {
        event.preventDefault();
        this.data = JSON.stringify(Object.fromEntries(new FormData(event.target as HTMLFormElement).entries()), null, 2);
      }
    }
    ```

    ```vue Vue icon="vuejs" expandable theme={"theme":{"light":"one-light","dark":"night-owl"}}
    <script setup lang="ts">
    import { ref } from "vue";
    import { BqButton, BqTimePicker } from "@beeq/vue";

    const data = ref("{}");

    function handleSubmit(event: Event) {
      data.value = JSON.stringify(Object.fromEntries(new FormData(event.target as HTMLFormElement).entries()), null, 2);
    }
    </script>

    <template>
      <form @reset="data = '{}'" @submit.prevent="handleSubmit">
        <BqTimePicker
          formValidationMessage="Choose a start time"
          name="startTime"
          required
        >
          <label slot="label">Start time</label>
        </BqTimePicker>
        <BqButton appearance="secondary" type="reset">Reset</BqButton>
        <BqButton type="submit">Submit</BqButton>
        <pre>{{ data }}</pre>
      </form>
    </template>
    ```
  </CodeGroup>
</CodeLivePreview>

## Best practices

<CardGroup cols={2}>
  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="check" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Do
    </span>

    Write labels that name the moment, such as "Departure time" or "Meeting starts", so people know which time they are setting.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="xmark" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Don't
    </span>

    Do not rely on the format hint alone to explain the field. Always provide a visible label.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="check" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Do
    </span>

    Match `precision` to the task. Most scheduling needs hours and minutes only; add seconds only for durations or precise logs.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="xmark" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Don't
    </span>

    Do not ask for seconds when nobody will use them. Every extra segment adds typing and scanning effort.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="check" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Do
    </span>

    Set `min`, `max`, and step values when business rules are known, so unavailable times are disabled before people pick them.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="xmark" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Don't
    </span>

    Do not mix clocks across a product. Pick the `hour-format` your audience expects and use it for every time picker.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="check" iconType="solid" size={20} color="var(--bq-stroke--success)" />

      Do
    </span>

    Use `require-confirm` when a picked time triggers an expensive or irreversible action, such as rescheduling a booking.
  </Card>

  <Card>
    <span className="flex items-center mr-2 text-lg font-medium" role="heading">
      <Icon className="mr-2" icon="xmark" iconType="solid" size={20} color="var(--bq-stroke--danger)" />

      Don't
    </span>

    Do not use a time picker for durations longer than a day or for picking a date and time together.
  </Card>
</CardGroup>

## Accessibility

* `bq-time-picker` is form-associated and delegates focus, so it participates in native forms and moves focus into its segmented field when the component receives focus.
* The segmented field is a labelled `group` described by the expected format and, when a constraint fails, by the validation message. Each hour, minute, second, and AM/PM control is a `spinbutton` with its own label, limits, value text, and roving tabindex, and exposes `aria-required` when the field is required.
* Each segment sets `aria-invalid="true"` for `validationStatus="error"` and native constraint failures, such as a missing required value or an incomplete, out-of-range, or off-step time. `aria-readonly` and `aria-disabled` reflect the `readonly` and `disabled` states.
* The panel carries `role="dialog"` and is named by `labels.panelLabel` ("Choose time" by default). The panel isn't modal.
* Each column is a `listbox` labelled by its visible header (`aria-labelledby`), so the spoken name matches what people see. Options expose `aria-selected`, and options outside `min`, `max`, or the steps expose `aria-disabled="true"`.
* The component announces the selected time, or that no time is selected, when focus enters the field.
* Press `Alt`+`ArrowDown` in the field, or Tab to the clock icon and press `Enter` or `Space`, to open the panel and move focus into it. Clicking the field opens the panel while keeping focus on the segment.
* In the panel, `ArrowUp` and `ArrowDown` move between options, `Home` and `End` jump to the first or last option, `PageUp` and `PageDown` move faster, and `ArrowLeft` and `ArrowRight` switch columns. `Enter` or `Space` picks an option, and `Escape` closes the panel and returns focus to the field.
* In `readonly` mode the segments stay focusable so screen reader users can read the value, but they can't be edited and the panel doesn't open.
* Always provide a visible label through the `label` slot, so the field has a programmatic name.
* When you translate the interface, translate `labels` too: segment names, button names and the panel name come from it.
* Validation states should never rely on color alone. Pair `validationStatus` with visible error text so screen reader users receive the same feedback as sighted users.

## API reference

### Properties

| Property | Attribute | Description | Type | Default |
| - | - | - | - | - |
| `autofocus` | `autofocus` | If `true`, the Time picker field will be focused on component render | `boolean` | `false` |
| `disableClear` | `disable-clear` | If `true`, the clear button won't be displayed | `boolean` | `false` |
| `disableNow` | `disable-now` | If `true`, the panel "Now" button won't be displayed | `boolean` | `false` |
| `disabled` | `disabled` | Indicates whether the Time picker is disabled or not | `boolean` | `false` |
| `distance` | `distance` | Distance (gutter) between the Time picker panel and the field | `number` | `8` |
| `form` | `form` | The ID of the form the field belongs to | `string` | `undefined` |
| `formValidationMessage` | `form-validation-message` | Native form validation message | `string` | `undefined` |
| `hourFormat` | `hour-format` | The clock used by the field and the panel: 24-hour (`"24"`) or 12-hour with an AM/PM period (`"12"`). It doesn't depend on the `locale` | `"12" \| "24"` | `"24"` |
| `hourStep` | `hour-step` | Step between selectable hours | `number` | `1` |
| `labels` | `labels` | Text of the column headers, AM/PM labels, buttons and accessible names, as an object or a JSON string. Missing keys fall back to the `locale` names or English text. See [Labels](#labels) | `TTimePickerLabels \| string` | `undefined` |
| `locale` | `locale` | Locale used for the field layout, separators, column headers and day period labels. The clock is set by `hour-format` | `Locale \| readonly (string \| Locale)[] \| string` | `"en-GB"` |
| `max` | `max` | Latest selectable time, in 24-hour format (`HH:mm` or `HH:mm:ss`). Ignored, together with `min`, when it is earlier than `min` | `string` | `undefined` |
| `min` | `min` | Earliest selectable time, in 24-hour format (`HH:mm` or `HH:mm:ss`). Ignored, together with `max`, when it is later than `max` | `string` | `undefined` |
| `minuteStep` | `minute-step` | Step between selectable minutes | `number` | `1` |
| `name` | `name` | Name submitted with the form data (required) | `string` | `undefined` |
| `open` | `open` | If `true`, the panel is visible | `boolean` | `false` |
| `panelHeight` | `panel-height` | Overrides the height of the Time picker panel | `string` | `"auto"` |
| `placement` | `placement` | Position of the Time picker panel | `"bottom" \| "bottom-end" \| "bottom-start" \| "left" \| "left-end" \| "left-start" \| "right" \| "right-end" \| "right-start" \| "top" \| "top-end" \| "top-start"` | `"bottom-end"` |
| `precision` | `precision` | Smallest unit edited and submitted: `hour` → `HH:00`, `minute` → `HH:mm`, `second` → `HH:mm:ss` | `"hour" \| "minute" \| "second"` | `"minute"` |
| `readonly` | `readonly` | If `true`, the value can be read and submitted but not changed | `boolean` | `false` |
| `requireConfirm` | `require-confirm` | If `true`, picks made in the panel (including "Now") are a draft until confirmed with the OK button or Enter. The field keeps showing the committed value until then. Escape or an outside click discards the draft | `boolean` | `false` |
| `required` | `required` | Whether a value must be entered before submitting the form | `boolean` | `false` |
| `secondStep` | `second-step` | Step between selectable seconds | `number` | `1` |
| `skidding` | `skidding` | Skidding between the panel and the field | `number` | `0` |
| `strategy` | `strategy` | Positioning strategy for the panel | `"absolute" \| "fixed"` | `"fixed"` |
| `validationStatus` | `validation-status` | Validation state applied to the field | `"error" \| "none" \| "success" \| "warning"` | `"none"` |
| `value` | `value` | The selected time, in 24-hour format: `HH:mm` (`HH:00` at hour precision) or `HH:mm:ss` at second precision | `string` | `undefined` |

### Events

| Event | Description | Type |
| - | - | - |
| `bqBlur` | Fired when focus leaves the Time picker. Moving focus between the field and the panel does not fire it | `CustomEvent<HTMLBqTimePickerElement>` |
| `bqChange` | Fired when the value is committed or cleared | `CustomEvent<{ value: string; el: HTMLElement }>` |
| `bqClear` | Fired when the value is cleared | `CustomEvent<HTMLBqTimePickerElement>` |
| `bqFocus` | Fired when focus enters the Time picker. Moving focus between the field and the panel does not fire it | `CustomEvent<HTMLBqTimePickerElement>` |

<Note>
  * In React, prefix events with `on`: `onBqBlur`, `onBqChange`, `onBqClear`, `onBqFocus`.
  * In Angular, use the event binding syntax: `(bqBlur)`, `(bqChange)`, `(bqClear)`, `(bqFocus)`.
  * In Vue, use the `@` shorthand: `@bqBlur`, `@bqChange`, `@bqClear`, `@bqFocus`.
</Note>

### Methods

| Method | Description | Signature |
| - | - | - |
| `clear()` | Clears the value and any pending validation state, then emits `bqClear`. Does nothing when the component is disabled or read-only | `clear() => Promise<void>` |

### Slots

| Slot | Description |
| - | - |
| `label` | Label displayed above the field |
| `prefix` | Optional content rendered before the value |
| `suffix` | Replaces the icon inside the clock trigger button; defaults to a clock icon. Use `labels.openPanel` to name the button |
| `clear-icon` | Replaces the default clear icon |

### Shadow parts

| Part | Description |
| - | - |
| `base` | Base wrapper for the component |
| `label` | Label slot container |
| `control` | Field control wrapper |
| `prefix` | Prefix slot container |
| `suffix` | Clock trigger button that hosts the suffix slot |
| `input` | Segmented time field group |
| `segment` | Editable hour, minute, second, or AM/PM segment |
| `segment-literal` | Locale-derived separator between time segments |
| `clear-btn` | Clear button |
| `time-trigger` | Clock icon trigger button |
| `button` | Any button rendered by the component |
| `panel` | Dropdown panel container |
| `container` | Panel content wrapper |
| `columns` | Wrapper of the panel columns |
| `column` | Scrollable list of options (hours, minutes, seconds, or AM/PM) |
| `column-header` | Header above a column; it stays in place while the column scrolls |
| `option` | Any option inside a column |
| `option-selected` | Selected option of a column |
| `footer` | Panel footer |
| `now-btn` | "Now" button |
| `confirm-btn` | Confirm (OK) button |

### CSS custom properties

<Expandable title="CSS variables" defaultOpen={false}>
  | Variable | Description | Default |
  | - | - | - |
  | `--bq-time-picker--background-color` | Time picker background color | `var(--bq-ui--primary)` |
  | `--bq-time-picker--border-color` | Time picker border color | `var(--bq-stroke--tertiary)` |
  | `--bq-time-picker--border-color-disabled` | Time picker border color when disabled | `var(--bq-stroke--secondary)` |
  | `--bq-time-picker--border-color-focus` | Time picker border color on focus | `var(--bq-stroke--brand)` |
  | `--bq-time-picker--border-color-danger` | Time picker border color when the validation status is `error` | `var(--bq-stroke--danger)` |
  | `--bq-time-picker--border-color-success` | Time picker border color when the validation status is `success` | `var(--bq-stroke--success)` |
  | `--bq-time-picker--border-color-warning` | Time picker border color when the validation status is `warning` | `var(--bq-stroke--warning)` |
  | `--bq-time-picker--border-radius` | Time picker border radius | `var(--bq-radius--s)` |
  | `--bq-time-picker--border-style` | Time picker border style | `solid` |
  | `--bq-time-picker--border-width` | Time picker border width | `1px` |
  | `--bq-time-picker--column-gap` | Space between the panel columns | `var(--bq-spacing-xs2)` |
  | `--bq-time-picker--column-header-text-color` | Text color of the column headers | `var(--bq-text--secondary)` |
  | `--bq-time-picker--column-height` | Height of the scrollable panel columns | `15rem` |
  | `--bq-time-picker--column-width` | Width of a panel column | `3.5rem` |
  | `--bq-time-picker--divider-color` | Color of the lines between the panel columns and above the footer | `var(--bq-stroke--primary)` |
  | `--bq-time-picker--gap` | Gap between field content and prefix/suffix | `var(--bq-spacing-xs)` |
  | `--bq-time-picker--icon-size` | Prefix/suffix/clear icon size | `1.5rem` |
  | `--bq-time-picker--label-margin-bottom` | Space below the label | `var(--bq-spacing-xs)` |
  | `--bq-time-picker--label-text-color` | Label text color | `var(--bq-text--primary)` |
  | `--bq-time-picker--label-text-size` | Label text size | `0.875rem` |
  | `--bq-time-picker--option-background-hover` | Hover background of a column option | `var(--bq-ui--secondary)` |
  | `--bq-time-picker--option-background-selected` | Background of the selected column option | `var(--bq-ui--brand)` |
  | `--bq-time-picker--option-height` | Height of a column option | `2.5rem` |
  | `--bq-time-picker--option-width` | Width of a column option | `3rem` |
  | `--bq-time-picker--option-radius` | Border radius of a column option | `var(--bq-radius--xs)` |
  | `--bq-time-picker--option-text-selected` | Text color of the selected column option | `var(--bq-text--on-brand, var(--bq-text--alt))` |
  | `--bq-time-picker--padding-end` | Field padding end | `var(--bq-spacing-m)` |
  | `--bq-time-picker--padding-start` | Field padding start | `var(--bq-spacing-m)` |
  | `--bq-time-picker--paddingY` | Field vertical padding | `var(--bq-spacing-s)` |
  | `--bq-time-picker--text-color` | Field text color | `var(--bq-text--primary)` |
  | `--bq-time-picker--text-placeholder-color` | Placeholder text color | `var(--bq-text--secondary)` |
  | `--bq-time-picker--text-size` | Field text size | `1rem` |
</Expandable>

<Tip>
  Learn more about [styling with shadow parts](/guides/styles#component-shadow-dom-parts) and [CSS custom properties](/guides/styles#global-css-custom-properties).
</Tip>

## Resources

<CardGroup cols={2}>
  <Card horizontal title="Interactive playground" icon="code" href="https://storybook.beeq.design/?path=/story/components-time-picker--default">
    Explore time picker variants, constraints, locales, and panel behavior in Storybook.
  </Card>

  <Card horizontal title="Source code" icon="github" href="https://github.com/Endava/BEEQ/tree/main/packages/beeq/src/components/time-picker">
    Browse the component implementation, styles, and tests on GitHub.
  </Card>
</CardGroup>


## Related topics

- [Date Picker](/components/date-picker.md)
- [Dropdown](/components/dropdown.md)
- [Changelog](/releases/changelog.md)
- [Alert](/components/alert.md)


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