# URL

Use `ui-url` for website fields, profile links, source references, support pages, and any workflow that captures navigable destinations. It inherits the shared field API for labels, help text, size, variant, readonly, disabled, and validation messaging while using URL-friendly input semantics.

## Import
```ts
import { UrlComponent } from 'ui';
```

## Basic URL fields
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { UrlComponent } from 'ui';

@Component({
  selector: 'app-url-basic-demo',
  standalone: true,
  imports: [FormsModule, UrlComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%">
      <div
        style="flex:1 1 18rem;min-width:16rem;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">Primary website</div>
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Good default for organization, product, or profile links.
          </div>
        </div>

        <ui-url
          label="Website URL"
          placeholder="https://example.com"
          helpText="Prefer full URLs with protocol when the link leaves the product."
        />
      </div>

      <div
        style="flex:1 1 18rem;min-width:16rem;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">Editable existing link</div>
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Shows the built-in clear action when a URL is already present.
          </div>
        </div>

        <ui-url
          label="Documentation link"
          placeholder="https://docs.example.com"
          [(ngModel)]="docsUrl"
          [ngModelOptions]="{ standalone: true }"
          helpText="Use clear to replace the URL quickly."
        />
      </div>
    </div>
  `,
})
export class UrlBasicDemoComponent {
  protected docsUrl = 'https://docs.example.com/guides/getting-started';
}
```

## Layout, size, and variant
```ts
import { Component } from '@angular/core';
import { UrlComponent } from 'ui';

@Component({
  selector: 'app-url-layout-demo',
  standalone: true,
  imports: [UrlComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:46rem">
      <div
        style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="flex:1 1 15rem;min-width:14rem">
          <ui-url
            label="Compact source link"
            size="small"
            inputVariant="filled-lighter"
            placeholder="https://"
          />
        </div>

        <div style="flex:1 1 15rem;min-width:14rem">
          <ui-url
            label="Partner page"
            labelPosition="before"
            size="medium"
            inputVariant="filled-gray"
            placeholder="https://partner.example.com"
          />
        </div>
      </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="font-size:0.9375rem;font-weight:600">Prominent published link</div>
        <ui-url
          label="Launch page URL"
          size="large"
          inputVariant="filled"
          placeholder="https://launch.example.com"
          helpText="Use a larger field when link editing is a primary part of the task."
        />
      </div>
    </div>
  `,
})
export class UrlLayoutDemoComponent {}
```

## Readonly, disabled, and inline error states
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { UrlComponent } from 'ui';

@Component({
  selector: 'app-url-states-demo',
  standalone: true,
  imports: [FormsModule, UrlComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%">
      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-url
          label="Readonly canonical URL"
          [readonly]="true"
          [(ngModel)]="readonlyUrl"
          [ngModelOptions]="{ standalone: true }"
          helpText="Useful when the link is visible here but managed somewhere else."
        />
      </div>

      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-url
          label="Disabled public page"
          [disabled]="true"
          placeholder="https://example.com"
          helpText="Disabled removes interaction entirely."
        />
      </div>

      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-url
          label="Inline format check"
          [(ngModel)]="draftUrl"
          [ngModelOptions]="{ standalone: true }"
          [errorText]="draftError"
          helpText="Example: https://product.example.com"
        />
      </div>
    </div>
  `,
})
export class UrlStatesDemoComponent {
  protected readonlyUrl = 'https://contoso.com/support/status';
  protected draftUrl = 'example';

  protected get draftError(): string {
    if (!this.draftUrl) {
      return '';
    }
    return /^https?:\/\//i.test(this.draftUrl) ? '' : 'Include http:// or https://.';
  }
}
```

## Validation with reactive forms
```ts
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { ButtonComponent, UrlComponent } from 'ui';

@Component({
  selector: 'app-url-validation-demo',
  standalone: true,
  imports: [ButtonComponent, ReactiveFormsModule, UrlComponent],
  template: `
    <form
      [formGroup]="linkForm"
      style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:34rem"
      (ngSubmit)="markTouched()"
    >
      <ui-url
        label="Design source URL"
        placeholder="https://www.figma.com/file/..."
        helpText="Required. Use a full URL to the working source."
        formControlName="sourceUrl"
        [errorText]="sourceError"
      />

      <div style="display:flex;flex-wrap:wrap;gap:0.75rem">
        <ui-button type="submit">Validate</ui-button>
        <ui-button type="button" appearance="outline" (click)="fillExample()"
          >Use example</ui-button
        >
      </div>
    </form>
  `,
})
export class UrlValidationDemoComponent {
  protected readonly linkForm = new FormGroup({
    sourceUrl: new FormControl('', {
      nonNullable: true,
      validators: [Validators.required],
    }),
  });

  protected get sourceError(): string {
    const control = this.linkForm.controls.sourceUrl;
    if (!control.touched && !control.dirty) {
      return '';
    }
    if (control.hasError('required')) {
      return 'URL is required.';
    }
    if (control.value && !/^https?:\/\//i.test(control.value)) {
      return 'Use a full URL starting with http:// or https://.';
    }
    return '';
  }

  protected markTouched(): void {
    this.linkForm.markAllAsTouched();
  }

  protected fillExample(): void {
    this.linkForm.controls.sourceUrl.setValue('https://www.figma.com/file/abc123/project-system');
    this.linkForm.controls.sourceUrl.markAsTouched();
  }
}
```

## Profile links form
```ts
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { ButtonComponent, UrlComponent } from 'ui';

@Component({
  selector: 'app-url-profile-form-demo',
  standalone: true,
  imports: [ButtonComponent, ReactiveFormsModule, UrlComponent],
  template: `
    <form
      [formGroup]="profileForm"
      style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%;max-width:54rem"
    >
      <div
        style="flex:1 1 22rem;min-width:18rem;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">Profile links</div>
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            URL fields often come in groups: website, portfolio, repository, or support page.
          </div>
        </div>

        <ui-url label="Website" placeholder="https://company.example" formControlName="website" />

        <ui-url
          label="GitHub repository"
          placeholder="https://github.com/org/repo"
          formControlName="github"
          inputVariant="filled-gray"
        />

        <ui-url
          label="Support page"
          placeholder="https://example.com/support"
          formControlName="support"
        />

        <div
          style="display:flex;gap:0.75rem;flex-wrap:wrap;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">Save links</ui-button>
          <ui-button type="button" variant="secondary" appearance="outline" (click)="reset()">
            Reset
          </ui-button>
        </div>
      </div>

      <div
        style="flex:0 0 18rem;min-width:16rem;padding:0.875rem 1rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background2-rest)"
      >
        <p
          style="margin:0 0 0.5rem;font-size:0.75rem;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;color:var(--color-neutral-foreground2-rest)"
        >
          Current links
        </p>
        <div
          style="display:flex;flex-direction:column;gap:0.5rem;font-size:0.875rem;line-height:1.4"
        >
          <div style="display:flex;justify-content:space-between;gap:1rem">
            <span style="color:var(--color-neutral-foreground2-rest)">Website</span>
            <strong style="font-weight:600;color:var(--color-neutral-foreground-rest)">{{
              profileForm.controls.website.value || 'None'
            }}</strong>
          </div>
          <div style="display:flex;justify-content:space-between;gap:1rem">
            <span style="color:var(--color-neutral-foreground2-rest)">GitHub</span>
            <strong style="font-weight:600;color:var(--color-neutral-foreground-rest)">{{
              profileForm.controls.github.value || 'None'
            }}</strong>
          </div>
          <div style="display:flex;justify-content:space-between;gap:1rem">
            <span style="color:var(--color-neutral-foreground2-rest)">Support</span>
            <strong style="font-weight:600;color:var(--color-neutral-foreground-rest)">{{
              profileForm.controls.support.value || 'None'
            }}</strong>
          </div>
        </div>
      </div>
    </form>
  `,
})
export class UrlProfileFormDemoComponent {
  protected readonly defaults = {
    website: 'https://contoso.com',
    github: 'https://github.com/contoso/design-system',
    support: 'https://contoso.com/support',
  };

  protected readonly profileForm = new FormGroup({
    website: new FormControl(this.defaults.website, { nonNullable: true }),
    github: new FormControl(this.defaults.github, { nonNullable: true }),
    support: new FormControl(this.defaults.support, { nonNullable: true }),
  });

  protected reset(): void {
    this.profileForm.reset(this.defaults);
  }
}
```

## Share destination panel
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ButtonComponent, UrlComponent } from 'ui';

@Component({
  selector: 'app-url-link-panel-demo',
  standalone: true,
  imports: [ButtonComponent, FormsModule, UrlComponent],
  template: `
    <div
      style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:42rem;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.375rem">
        <div style="font-size:1rem;font-weight:600">Share destination panel</div>
        <div
          style="font-size:0.875rem;color:var(--color-neutral-foreground2-rest);line-height:1.45"
        >
          A realistic URL surface combines the destination field, context about where the link will
          be used, and immediate next-step actions.
        </div>
      </div>

      <ui-url
        label="Destination URL"
        placeholder="https://launch.example.com"
        [(ngModel)]="destinationUrl"
        [ngModelOptions]="{ standalone: true }"
        helpText="This link will be shared in the release announcement."
      />

      <div
        style="display:flex;gap:0.75rem;flex-wrap:wrap;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">Save link</ui-button>
        <ui-button
          type="button"
          variant="secondary"
          appearance="outline"
          (click)="destinationUrl = ''"
        >
          Clear
        </ui-button>
      </div>
    </div>
  `,
})
export class UrlLinkPanelDemoComponent {
  protected destinationUrl = 'https://launch.example.com/2026/spring';
}
```

## Accessibility

### Label and name
Prefer a visible `label` so the link purpose is explicit, especially when several URL fields appear together. Help and error text contribute through `aria-describedby`.

### Native URL semantics
The inner input uses native `type="url"`, which helps browsers apply URL-specific validation heuristics and aligns the field with browser autofill expectations. When `autocomplete` is omitted, the inner input falls back to `url`.

### Keyboard and actions
This is a standard text-entry field backed by a native URL input. Clear and link affordances are exposed in the field chrome when the field is editable.

| Aspect | Behavior |
| --- | --- |
| focus | native url input receives focus |
| typing | native url input behavior |
| clear action | appears only when the field has a value and is editable |
| link action | stays visible while editable to reinforce the destination purpose |
| readonly / disabled | actions are hidden and direct editing is blocked |
