# Week

Use `ui-week` when planning, reporting, or scheduling is organized by ISO week instead of a specific date. It is stronger than a plain text field because it can present a week list, enforce valid ISO week values, and keep the chosen week readable in a user-facing format.

## Import
```ts
import { WeekComponent, type WeekDisplayFormat } from 'ui';
```

## Basic week selection
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ButtonComponent, WeekComponent } from 'ui';

@Component({
  selector: 'app-week-basic-demo',
  standalone: true,
  imports: [FormsModule, ButtonComponent, WeekComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem;max-width:22rem">
      <ui-week
        label="Reporting week"
        placeholder="Select week"
        [(ngModel)]="value"
        [ngModelOptions]="{ standalone: true }"
      />

      <div
        style="display:flex;flex-wrap:wrap;gap:0.75rem;align-items:center;padding:0.75rem 0.875rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:0.875rem;background:var(--color-neutral-background-rest)"
      >
        <ui-button type="button" appearance="subtle" (click)="value = ''">Clear</ui-button>
        <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest)">
          {{ value || 'No week selected.' }}
        </span>
      </div>
    </div>
  `,
})
export class WeekBasicDemoComponent {
  protected value = '2026-W20';
}
```

## Display formats
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { WeekComponent } from 'ui';

@Component({
  selector: 'app-week-formats-demo',
  standalone: true,
  imports: [FormsModule, WeekComponent],
  template: `
    <div
      style="display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1rem;align-items:start"
    >
      <ui-week
        label="Date range"
        placeholder="Select week"
        displayFormat="date-range"
        [(ngModel)]="rangeValue"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-week
        label="Week / year"
        placeholder="Select week"
        displayFormat="week-year"
        [(ngModel)]="weekYearValue"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-week
        label="ISO format"
        placeholder="Select week"
        displayFormat="iso"
        [(ngModel)]="isoValue"
        [ngModelOptions]="{ standalone: true }"
      />
    </div>
  `,
})
export class WeekFormatsDemoComponent {
  protected rangeValue = '2026-W20';
  protected weekYearValue = '2026-W21';
  protected isoValue = '2026-W22';
}
```

## Min and max constraints
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { WeekComponent } from 'ui';

@Component({
  selector: 'app-week-constraints-demo',
  standalone: true,
  imports: [FormsModule, WeekComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem;max-width:22rem">
      <ui-week
        label="Release week"
        placeholder="Select week"
        min="2026-W18"
        max="2026-W26"
        [(ngModel)]="value"
        [ngModelOptions]="{ standalone: true }"
      />

      <div
        style="display:flex;flex-direction:column;gap:0.375rem;padding:0.75rem 0.875rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:0.875rem;background:var(--color-neutral-background-rest);font-size:0.75rem;color:var(--color-neutral-foreground2-rest)"
      >
        <span>Allowed window: 2026-W18 to 2026-W26</span>
        <span>Selected: {{ value || 'None' }}</span>
      </div>
    </div>
  `,
})
export class WeekConstraintsDemoComponent {
  protected value = '2026-W20';
}
```

## Size and field states
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { WeekComponent } from 'ui';

@Component({
  selector: 'app-week-states-demo',
  standalone: true,
  imports: [FormsModule, WeekComponent],
  template: `
    <div
      style="display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1rem;align-items:start"
    >
      <ui-week
        label="Small"
        placeholder="Select week"
        size="small"
        [(ngModel)]="smallValue"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-week
        label="Readonly"
        placeholder="Select week"
        [readonly]="true"
        [(ngModel)]="readonlyValue"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-week
        label="Disabled"
        placeholder="Select week"
        [disabled]="true"
        [(ngModel)]="disabledValue"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-week
        label="Required with helper"
        placeholder="Select week"
        helpText="Choose the delivery week."
        [required]="true"
        [(ngModel)]="requiredValue"
        [ngModelOptions]="{ standalone: true }"
      />
    </div>
  `,
})
export class WeekStatesDemoComponent {
  protected smallValue = '2026-W19';
  protected readonlyValue = '2026-W21';
  protected disabledValue = '2026-W24';
  protected requiredValue = '';
}
```

## Reactive form integration
```ts
import { Component, computed } from '@angular/core';
import { ReactiveFormsModule, FormControl, Validators } from '@angular/forms';
import { ButtonComponent, MessageBarComponent, WeekComponent } from 'ui';

@Component({
  selector: 'app-week-reactive-form-demo',
  standalone: true,
  imports: [ReactiveFormsModule, ButtonComponent, MessageBarComponent, WeekComponent],
  template: `
    <div
      style="display:flex;flex-direction:column;gap:1rem;max-width:24rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <div style="display:flex;flex-direction:column;gap:0.25rem">
        <div style="font-size:0.9375rem;font-weight:600">Sprint planning</div>
        <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
          Pick the sprint week and keep the field inside a normal reactive form flow.
        </div>
      </div>

      <ui-week
        label="Sprint start week"
        placeholder="Select week"
        helpText="Use the ISO sprint week from the roadmap."
        [required]="true"
        [formControl]="weekControl"
      />

      @if (weekControl.invalid && weekControl.touched) {
        <ui-message-bar
          title="Week required"
          message="Choose the sprint week before you continue."
          variant="warning"
          appearance="subtle"
          [dismissible]="false"
        />
      }

      <div
        style="display:flex;flex-wrap:wrap;gap:0.75rem;align-items:center;padding:0.75rem 0.875rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:0.875rem;background:var(--color-neutral-background-rest)"
      >
        <ui-button type="button" variant="primary" [disabled]="weekControl.invalid">
          Save sprint
        </ui-button>
        <ui-button type="button" appearance="subtle" (click)="reset()">Reset</ui-button>
        <span style="font-size:0.75rem;color:var(--color-neutral-foreground2-rest)">
          {{ summary() }}
        </span>
      </div>
    </div>
  `,
})
export class WeekReactiveFormDemoComponent {
  protected readonly weekControl = new FormControl<string | null>('2026-W23', {
    nonNullable: false,
    validators: [Validators.required],
  });

  protected readonly summary = computed(() => this.weekControl.value || 'No sprint week selected.');

  protected reset(): void {
    this.weekControl.reset('2026-W23');
  }
}
```

## Planning panel composition
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ButtonComponent, MessageBarComponent, TagComponent, WeekComponent } from 'ui';

@Component({
  selector: 'app-week-planning-panel-demo',
  standalone: true,
  imports: [FormsModule, ButtonComponent, MessageBarComponent, TagComponent, WeekComponent],
  template: `
    <div
      style="display:grid;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr));gap:1rem;align-items:start;max-width:46rem"
    >
      <div
        style="display:flex;flex-direction:column;gap:1rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="display:flex;flex-direction:column;gap:0.25rem">
          <div style="font-size:0.9375rem;font-weight:600">Launch preparation</div>
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Weeks are useful when planning releases, reporting cycles, and recurring operational
            work.
          </div>
        </div>

        <ui-week
          label="Go-live week"
          placeholder="Select week"
          displayFormat="week-year"
          [(ngModel)]="week"
          [ngModelOptions]="{ standalone: true }"
        />

        <ui-message-bar
          title="Release note"
          message="The selected week should match the deployment and communication timeline."
          variant="info"
          appearance="subtle"
          [dismissible]="false"
        />
      </div>

      <div
        style="display:flex;flex-direction:column;gap:0.875rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="display:flex;flex-wrap:wrap;gap:0.5rem">
          <ui-tag text="Operations" appearance="filled" variant="secondary" />
          <ui-tag text="Weekly cadence" appearance="subtle" variant="info" />
          <ui-tag text="Ready to schedule" appearance="subtle" variant="success" />
        </div>

        <div style="display:flex;flex-direction:column;gap:0.375rem">
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Selected week
          </div>
          <div style="font-size:0.9375rem;font-weight:600">{{ week || 'Not selected' }}</div>
        </div>

        <div
          style="display:flex;flex-wrap:wrap;gap:0.75rem;align-items:center;padding:0.75rem 0.875rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:0.875rem;background:var(--color-neutral-background-rest)"
        >
          <ui-button type="button" variant="primary">Create plan</ui-button>
          <ui-button type="button" appearance="subtle" (click)="week = ''">Reset</ui-button>
        </div>
      </div>
    </div>
  `,
})
export class WeekPlanningPanelDemoComponent {
  protected week = '2026-W25';
}
```

## Accessibility

### Input and popup behavior
`ui-week` behaves like a text field on desktop and can fall back to a native `type="week"` input on mobile when `useNativeOnMobile` is enabled.

| Mode | Behavior |
| --- | --- |
| desktop text input | exposes `aria-haspopup="dialog"` and `aria-expanded` |
| mobile native week input | relies on native platform week input semantics |
| disabled or readonly | blocks opening or changing the value |

### Keyboard
Keyboard behavior follows the field and popup model rather than a custom roving picker.

| Key | Action |
| --- | --- |
| `Tab` / `Shift+Tab` | moves through the field and overlay controls |
| `Enter` / click on trigger actions | opens the week picker panel on desktop |
| button activation | selects a week or runs footer actions like clear or this week |

### Labels and guidance
Use explicit labels such as sprint week, reporting week, or release week so users understand the ISO-week context. When the valid window is narrow, add helper text or nearby status text that explains the allowed range.
