Skip to content

Custom Input

Typescript

Below is an example of a custom input component in TypeScript. The component extends the WrappedFormControl class and utilizes the provideValueAccessor function to provide the ControlValueAccessor interface.

The WrappedFormControl class is used to provide the ControlValueAccessor interface to the component and to provide the FormControl instance to the component.

ts
import { Component, Input } from '@angular/core';

import { WrappedFormControl, provideValueAccessor } from '@k5cjs/forms';

@Component({
  selector: 'app-custom-input',
  templateUrl: './custom-input.component.html',
  styleUrls: ['./custom-input.component.scss'],
  providers: [provideValueAccessor(CustomInputComponent)],
})
export class CustomInputComponent extends WrappedFormControl {
  @Input() name: string | undefined;
  @Input() placeholder: string | undefined;
  @Input() label: string | undefined;
  @Input() type: 'text' | 'email' | 'password' = 'text';
}
import { Component, Input } from '@angular/core';

import { WrappedFormControl, provideValueAccessor } from '@k5cjs/forms';

@Component({
  selector: 'app-custom-input',
  templateUrl: './custom-input.component.html',
  styleUrls: ['./custom-input.component.scss'],
  providers: [provideValueAccessor(CustomInputComponent)],
})
export class CustomInputComponent extends WrappedFormControl {
  @Input() name: string | undefined;
  @Input() placeholder: string | undefined;
  @Input() label: string | undefined;
  @Input() type: 'text' | 'email' | 'password' = 'text';
}

The HTML template for the custom input component is as follows:

html
<kc-form-field class="field">
  <!-- <form-label *ngIf="label" [value]="label" label></form-label> -->

  <ng-container ngProjectAs="[before]">
    <ng-content select="[before]"></ng-content>
  </ng-container>

  <kc-form-field-placeholder *ngIf="placeholder" [value]="placeholder"></kc-form-field-placeholder>

  <input ngDefaultControl kc-input [name]="name" tabindex="0" placeholder="" />

  <ng-container ngProjectAs="[after]">
    <ng-content select="[after]"></ng-content>
  </ng-container>
</kc-form-field>
<kc-form-field class="field">
  <!-- <form-label *ngIf="label" [value]="label" label></form-label> -->

  <ng-container ngProjectAs="[before]">
    <ng-content select="[before]"></ng-content>
  </ng-container>

  <kc-form-field-placeholder *ngIf="placeholder" [value]="placeholder"></kc-form-field-placeholder>

  <input ngDefaultControl kc-input [name]="name" tabindex="0" placeholder="" />

  <ng-container ngProjectAs="[after]">
    <ng-content select="[after]"></ng-content>
  </ng-container>
</kc-form-field>

Here are the styles for the custom input component in both Tailwind and regular SCSS:

scss
.field {
  @apply w-full
    m-0
    py-2
    px-1;
}

input {
  @apply w-full
    m-0
    p-0
    border-none
    box-border
    bg-transparent
    outline-none
    placeholder-slate-400
    truncate;

  &:-webkit-autofill,
  &:-webkit-autofill:hover,
  &:-webkit-autofill:focus {
    @apply [background:transparent]
      bg-[#fff]
      shadow-inner
      shadow-transparent
      transition-colors
      duration-[5000s];
  }

  /**
   * for removing the highlight on iOS
   */
  -webkit-tap-highlight-color: transparent;

  &:disabled {
    /**
     * for removing opacity on disabled inputs in Safari
     */
    @apply opacity-100;
  }
}
.field {
  @apply w-full
    m-0
    py-2
    px-1;
}

input {
  @apply w-full
    m-0
    p-0
    border-none
    box-border
    bg-transparent
    outline-none
    placeholder-slate-400
    truncate;

  &:-webkit-autofill,
  &:-webkit-autofill:hover,
  &:-webkit-autofill:focus {
    @apply [background:transparent]
      bg-[#fff]
      shadow-inner
      shadow-transparent
      transition-colors
      duration-[5000s];
  }

  /**
   * for removing the highlight on iOS
   */
  -webkit-tap-highlight-color: transparent;

  &:disabled {
    /**
     * for removing opacity on disabled inputs in Safari
     */
    @apply opacity-100;
  }
}
scss
.field {
  width: 100%;
  margin: 0;
  padding: 0.5rem 0.25rem;
}

input {
  width: 100%;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  border-style: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  background-color: transparent;
  outline: 0;

  &:-webkit-autofill,
  &:-webkit-autofill:hover,
  &:-webkit-autofill:focus {
    box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 6%);
    background: transparent;
    background-color: #fff;
    transition-duration: 5000s;
    transition-property: background-color, border-color, color, fill, stroke;
  }

  /**
   * for removing the highlight on iOS
   */
  -webkit-tap-highlight-color: transparent;

  &:disabled {
    /**
     * for removing opacity on disabled inputs in Safari
     */
    opacity: 1;
  }
}
.field {
  width: 100%;
  margin: 0;
  padding: 0.5rem 0.25rem;
}

input {
  width: 100%;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  border-style: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  background-color: transparent;
  outline: 0;

  &:-webkit-autofill,
  &:-webkit-autofill:hover,
  &:-webkit-autofill:focus {
    box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 6%);
    background: transparent;
    background-color: #fff;
    transition-duration: 5000s;
    transition-property: background-color, border-color, color, fill, stroke;
  }

  /**
   * for removing the highlight on iOS
   */
  -webkit-tap-highlight-color: transparent;

  &:disabled {
    /**
     * for removing opacity on disabled inputs in Safari
     */
    opacity: 1;
  }
}