# `hb-input-datetime`

**Category:** inputs · **Tags:** inputs

## Overview

`hb-input-datetime` is a custom element that composes **`hb-input-date`** and several **`hb-input-number`** instances into one Bulma **`field is-grouped is-grouped-multiline`** row: a calendar date, then hours, minutes, and (by default) seconds, separated by colons. The host derives a single **ISO 8601** string (via `Date#toISOString()`) from the combined local date and time and reports it through the **`setVal`** custom event together with a **`valid`** flag.

The implementation registers the child packages **`@htmlbricks/hb-input-date`** and **`@htmlbricks/hb-input-number`** (same version as the bundle) so nested elements resolve correctly.

## Custom element

| Name | Tag |
| --- | --- |
| `hb-input-datetime` | `<hb-input-datetime …></hb-input-datetime>` |

## Host attributes and properties

Web component **attributes are strings**. Pass complex data as a **JSON string** (or set the `schemaentry` property to an object from JavaScript). Boolean-like host flags use **`yes`** / **`no`** where noted.

| Name | Required | Description |
|------|----------|-------------|
| `id` | No | Optional id on the host element. |
| `style` | No | Optional inline styles on the host. |
| `schemaentry` | Yes* | JSON (string or object) describing the field; see [Schema](#schema). If parsing fails, nothing is rendered. |
| `show_validation` | No | **`yes`** or **`no`** (default **`no`**). When **`yes`**, and the combined value is invalid while `validationTip` is set, a Bulma **`help is-danger`** line is shown (exposed as a CSS `::part`). |

\*Consumers should always supply a valid `schemaentry` the parser can read; invalid JSON yields an empty host.

## Schema

`schemaentry` follows the shared form row shape (`FormSchemaEntryShared`) with `params` narrowed to **`InputDatetimeParams`**. Keys that **this component reads** are:

| Key | Effect |
|-----|--------|
| `id` | **Required.** Included on every **`setVal`** `detail`. |
| `value` | Optional initial value. Coerced with `new Date(...)`. When the schema fingerprint changes and `value` is present, the host splits it into date (`YYYY-MM-DD`), hours, minutes, and seconds for the sub-controls. Very small or very large numeric timestamps are ignored (internal guard on `valueOf()`). |
| `required` | When **truthy**, `valid` is **`false`** until a full ISO datetime can be built **and** it lies within optional `params.min` / `params.max` (inclusive, compared with `Date#valueOf()`). When **falsy**, `valid` stays **`true`** (including empty input). |
| `disabled` | When **truthy**, inner `hb-input-date` / `hb-input-number` entries are built with `disabled: true`. |
| `validationTip` | Message shown in **`help is-danger`** when `show_validation` is **`yes`** and `valid` is **`false`**. |
| `params` | See [Datetime params](#datetime-params-inputdatetimeparams). |

Other keys allowed by the shared type (for example `label`, `placeholder`, `type`) may be present for larger forms or tooling; **this component does not render a label or placeholder** from `schemaentry`—only the grouped controls and optional validation help.

### Datetime params (`InputDatetimeParams`)

| Key | Type | Description |
|-----|------|-------------|
| `min` | `string \| number` | Passed to `new Date(...)`. With **`required`**, the composed instant must be **≥** this bound. |
| `max` | `string \| number` | Passed to `new Date(...)`. With **`required`**, the composed instant must be **≤** this bound. |
| `removeSeconds` | `boolean` | When truthy, the seconds **`hb-input-number`** is **not** rendered. Seconds still default to **0** when the user edits hours or minutes so the ISO string can be formed. |

## Value and validation behavior

- The derived **`value`** is **undefined** until **date**, **hours**, **minutes**, and **seconds** are all set (seconds may be **0**). The implementation builds a local datetime string `YYYY-MM-DD HH:mm:ss` and converts it with `new Date(...).toISOString()`.
- Changing the hour control initializes **minutes** and **seconds** to **0** if they were unset; changing **minutes** initializes **seconds** to **0** if unset.
- **`setVal`** is emitted when **`value`**, **`valid`**, or **`id`** changes, with deduplication so identical payloads are not fired twice in a row.

## Events

| Event | `detail` | Notes |
|-------|----------|--------|
| `setVal` | `{ value: string \| undefined; valid: boolean; id: string }` | Fired whenever the composed value or validity changes (after deduplication). `value` is **undefined** until date, hours, minutes, and seconds are all set (seconds may be `0`). |

There is no **`clickEnter`** event on this component (composed child elements handle their own keyboards); rely on **`setVal`** for live value and validity updates.

## Styling

### Bulma in the shadow root

`styles/bulma.scss` forwards Bulma form modules **`form/shared`**, **`form/input-textarea`**, and **`form/tools`**, with the light theme applied on **`:host`**. Nested **`hb-input-date`** / **`hb-input-number`** elements ship their own shadows and input styling.

### Theme variables (`:host`)

These tokens are documented for consumers in `extra/docs.ts` (`styleSetup.vars`):

| CSS variable | Role |
|--------------|------|
| `--bulma-text` | Grouped labels context and validation help text. |
| `--bulma-border` | Borders on the composed date/time controls (via children). |
| `--bulma-danger` | Invalid outline and **`help is-danger`**. |
| `--bulma-success` | Success styling on children when validation display is enabled. |
| `--bulma-scheme-main` | Surface behind the nested web components. |

See [Bulma CSS variables](https://bulma.io/documentation/features/css-variables/) for global Bulma tuning.

### CSS parts

| Part | Description |
|------|-------------|
| `invalid-feedback` | The **`p.help.is-danger`** node shown when `show_validation="yes"` and the combined value is invalid. |

## Typings

Authoring types live in **`types/webcomponent.type.d.ts`**: **`InputDatetimeParams`**, **`FormSchemaEntry`**, **`Component`**, **`Events`**.

## Examples

### From JavaScript (recommended)

Setting `schemaentry` as an object avoids heavy HTML escaping.

```html
<hb-input-datetime id="event_start"></hb-input-datetime>
<script>
  const el = document.getElementById("event_start");
  el.addEventListener("setVal", (e) => {
    console.log(e.detail.value, e.detail.valid, e.detail.id);
  });
  el.schemaentry = JSON.stringify({
    id: "starts_at",
    label: "Start",
    required: true,
    validationTip: "Choose a complete date and time within the allowed range.",
    params: {
      removeSeconds: true,
      min: "2024-01-01T00:00:00.000Z",
      max: "2024-12-31T23:59:59.999Z",
    },
  });
</script>
```

### From HTML (JSON attribute)

```html
<hb-input-datetime
  schemaentry='{"id":"starts_at","required":true,"params":{"removeSeconds":true}}'
  show_validation="yes"
></hb-input-datetime>
```

## Peer dependencies (nested packages)

Declared in `extra/docs.ts` for bundling and documentation:

- `hb-input-date`
- `hb-input-number`
