To generate an aminated credit card form in Angular, you can modify the app.module.ts file as follows:

Final Screen animated credit card

Final Screen animated credit card for the below sample.

Card

Card

In ngModule

TypeScript
@NgModule({
  declarations: [AppComponent], // Components, directives, and pipes that belong to this NgModule.
  imports: [
    CommonModule, // Provides commonly used directives, pipes, and services.
    AppRoutingModule, // The routing module for the application.
    BrowserAnimationsModule, // Module for providing animations support in Angular.
    FormsModule, // Module for two-way data binding using ngModel directive.
    ReactiveFormsModule // Module for reactive forms support.
  ],
  schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA], // Defines the schema to be used for components.
  bootstrap: [AppComponent] // The main component to be bootstrapped when this NgModule is bootstrapped.
})

In (app.component.ts)

TypeScript
@Component({
  selector: 'app-root', // The CSS selector that identifies this component in a template.
  encapsulation: ViewEncapsulation.None, // Defines how the styles of the component should be encapsulated. 'None' means no encapsulation.
  templateUrl: './app.component.html', // The URL of the template file for this component.
  styleUrls: ['./app.component.scss'], // An array of URLs of the style files for this component.
  animations: [ // An array of animation definitions for this component.
    trigger('flipState', [ // Defines an animation trigger named 'flipState'.
      state('active', style({ // Defines a state named 'active' with a specific style.
        transform: 'rotateY(179deg)' // CSS transformation to rotate the element.
      })),
      state('inactive', style({ // Defines a state named 'inactive' with a specific style.
        transform: 'rotateY(0)' // CSS transformation to rotate the element back to its original position.
      })),
      transition('active => inactive', animate('500ms ease-out')), // Defines a transition from 'active' to 'inactive' state with specific animation.
      transition('inactive => active', animate('500ms ease-in')) // Defines a transition from 'inactive' to 'active' state with specific animation.
    ])
  ]
})

In the below session, continue the app component.

Added the CardDetails object to get the card info, and while clearing, the object was reset to the initial state.

TypeScript
export class AppComponent {
  isShowBackCard: boolean = false;
  flip: string = 'inactive';
cardDetails:any=
{
  Name:null,
  CardNumber:null,
  CVV:null,
  ExpiryMonth:2,
  ExpiryYear:24
};
  toggleFlip() {
    this.flip ='active';
  }
  toggleFront()
  {
    this.flip =  'inactive';
  }
  constructor() {}
  Clear()
  {
    this.cardDetails=
    {
      Name:null,
      CardNumber:null,
      CVV:null,
      ExpiryMonth:2,
      ExpiryYear:24
    };
  }
  title = 'card-test';
}

In (app.component.html)

Here, we have two sections: one credit card front and back design and form with validation using template-driven forms.

Credit card design

HTML / XML
<main class="main">
  <div class="content">
    <div>
      <div class="tp-box" [@flipState]="flip">
        <div class="front-card" *ngIf="flip === 'inactive'">
          <p class="card-number">CARD NUMBER</p>
          <p class="card-number">{{!cardDetails.CardNumber? "XXXX-XXXX-XXXX-XXXX" :cardDetails.CardNumber}}</p>
          <div class="info-container row">
            <div class="col-md-9">
              <p class="cardholder-name ">CARD HOLDER NAME</p>
              <p class="cardholder-name">{{!cardDetails.Name? "YYYYYYY YYYYYYYY" :cardDetails.Name}}</p>
            </div>
            <div class="col-md-3">
              <p class="exp-date ">EXPIRY (MM/YY)</p>
              <p class="exp-date ">{{cardDetails.ExpiryMonth}}/{{cardDetails.ExpiryYear}}</p>
            </div>
          </div>
        </div>
        <div class="back-card" *ngIf="flip === 'active'">
          <p class="cvc">{{cardDetails.CVV}}</p>
        </div>
      </div>
      <div class="panel panel-default card-glass">
        <div class="panel-heading no-bg-color">
          <h1 class="or-color">Enter Card Details</h1>
        </div>
        <div class="panel-body">
          <div class="right-payment-sec">
            <form #cardForm="ngForm" autocomplete="off" name="cardForm" (ngSubmit)="cardForm.valid">
              <div class="row">
                <div class="col-lg-12 col-xs-12">
                  <div class="form-group">
                    <label class="no-bg-color" for="name">Name On Card</label>
                    <input type="text" class="form-control no-bg-color"
                      [ngClass]="{ 'has-error': cardForm.submitted && name.invalid }" #name="ngModel" id="name"
                      [(ngModel)]="cardDetails.Name" required autofocus name="name" placeholder="Name On Card">
                    <div *ngIf="cardForm.submitted && name.invalid" class="">
                      <label class="control-label error-message" *ngIf="name.errors?.['required']"><i
                          class="fa fa-times"></i> Required</label>
                    </div>
                  </div>
                </div>
                <div class="col-lg-12 col-xs-12">
                  <div class="form-group">
                    <label class="no-bg-color" for="cardnumber">Card Number</label>
                    <input type="number" class="form-control no-bg-color" #cardnumber="ngModel" id="cardnumber"
                      [(ngModel)]="cardDetails.CardNumber" name="cardnumber"
                      onKeyPress="if(this.value.length==16) return false;" required
                      [ngClass]="{ 'has-error': cardForm.submitted && cardnumber.invalid }"
                      placeholder="XXXX-XXXX-XXXX-XXXX">
                    <div *ngIf="cardForm.submitted && cardnumber.invalid" class="">
                      <label class="control-label error-message" *ngIf="cardnumber.errors?.['required']"><i
                          class="fa fa-times"></i> Required</label>
                    </div>
                  </div>
                </div>
                <div class="col-lg-6 col-md-6 xol-sm-6 col-xs-12 card-infos-container">
                  <label class="no-bg-color" for="expiry">Expiration (MM/YY)</label>

                  <div class="form-group date-container" id="date">
                    <div class="date">

                      <input type="number" class="form-control no-bg-color " placeholder="MM" #expiryMonth="ngModel"
                        [ngClass]="{ 'has-error': cardForm.submitted && expiryMonth.invalid }" id="expiryMonth"
                        [(ngModel)]="cardDetails.ExpiryMonth" name="expiryMonth" [min]="1" [max]="12" required>
                      <input type="number" class="form-control no-bg-color" placeholder="YY" #expiryYear="ngModel"
                        [ngClass]="{ 'has-error': cardForm.submitted && expiryYear.invalid }" id="expiryYear"
                        [(ngModel)]="cardDetails.ExpiryYear" name="expiryYear" [min]="01" [max]="99" required>

                    </div>
                    <div *ngIf="cardForm.submitted && (expiryMonth.invalid||expiryYear.invalid)" class="">
                      <label class="control-label error-message" *ngIf="expiryMonth.errors?.['required']"><i
                          class="fa fa-times"></i> Required</label>
                      <label class="control-label error-message" *ngIf="expiryMonth.errors?.['min']"><i
                          class="fa fa-times"></i> month 01-12 only</label>
                      <label class="control-label error-message" *ngIf="expiryMonth.errors?.['max']"><i
                          class="fa fa-times"></i> month 01-12 only</label>
                      <label class="control-label error-message" *ngIf="expiryYear.errors?.['required']"><i
                          class="fa fa-times"></i> Required</label>
                      <label class="control-label error-message" *ngIf="expiryYear.errors?.['min']"><i
                          class="fa fa-times"></i> Year 01-99 only</label>
                      <label class="control-label error-message" *ngIf="expiryYear.errors?.['max']"><i
                          class="fa fa-times"></i> Year 01-99 only</label>
                    </div>
                  </div>
                </div>
                <div class="col-lg-3 col-md-3 xol-sm-6 col-xs-12">
                  <div class="form-group">
                    <label class="no-bg-color" for="cvv">CCV</label>
                    <input type="number" class="form-control no-bg-color" #cvv="ngModel"
                      [ngClass]="{ 'has-error': cardForm.submitted && cvv.invalid }" id="cvv"
                      [(ngModel)]="cardDetails.CVV" name="cvv" required
                      (focus)="$event.stopPropagation();$event.preventDefault();toggleFlip()"
                      (blur)="$event.stopPropagation();$event.preventDefault();toggleFront()"
                      onKeyPress="if(this.value.length==3) return false;" placeholder="XXX">
                    <div *ngIf="cardForm.submitted && cvv.invalid" class="">
                      <label class="control-label error-message" *ngIf="cvv.errors?.['required']"><i
                          class="fa fa-times"></i> Required</label>
                    </div>
                  </div>
                </div>

                <div class="modal-footer">
                  <div class="form-group">
                    <button type="submit" class="btn btn-primary button-form" style="margin-right: 10px ;">Save</button>
                    <button type="button" class="btn btn-primary button-form" (click)="Clear()">Clear</button>
                  </div>
                </div>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
  </div>
</main>

app.component.scss

CSS
.background {
    width: 100%;
    height: 47.5vw;
    background-image: url(../assets/Credit-card-bro.svg), linear-gradient(to right, #00e7ff, #634d38);
    background-repeat: no-repeat;
    background-size: cover;
}

.card-glass {
    backdrop-filter: blur(3px) saturate(113%);
    -webkit-backdrop-filter: blur(3px) saturate(113%);
    background-color: rgba(255, 255, 255, 0);
    border-radius: 12px;
    border: 2px solid rgb(123 107 107);
}

input {
    border: 1px solid rgb(123 107 107);
}

.no-bg-color {
    background-color: transparent !important;
    font-size: medium;
    color: #df7017;
}

.or-color {
    color: #df7017;
}

.front-card {
    -webkit-transform: rotateY(0deg);
    -ms-transform: rotateY(0deg);
    transform: rotateY(0deg);
    background-image: url(../assets/1234.png);
    margin-left: 19%;
    // display: flex;
    // flex-direction: column;
    justify-content: space-around;
    border-radius: 8px;

    //  *{
    // margin-left: 1.5rem;
    // margin-top: 10.5rem;
    //  }
    .exp-date {
        font-size: 2rem;
    }

    .card-number {
        font-size: 2rem;
        margin-left: 1.5rem;
    }

    .cardholder-name {
        margin: 0;
        font-size: 2rem;
    }

    .info-container {

        width: 85%;
        // display: flex;
        // justify-content: space-between;
        margin-left: 1.5rem;
        margin-top: 6.5rem;
        font-family: sans-serif;
        font-weight: lighter;
        text-transform: uppercase;
    }

    img {
        width: 20%;
        height: 20%;
    }
}

.back-card {
    background-image: url(../assets/bg-card-back.png);
    display: flex;
    align-items: center;
    justify-content: end;
    -webkit-transform: rotateY(-180deg);
    -ms-transform: rotateY(-180deg);
    transform: rotateY(-180deg);
    margin-left: 19%;
    backface-visibility: hidden;

    p {
        margin-right: 6rem;
        font-size: medium;
    }
}

.back-card,
.front-card {
    background-repeat: no-repeat;
    background-size: cover;
    position: absolute;
    top: 0;
    left: 0;
    width: 447px;
    height: 245px;

    color: whitesmoke;
}

@media screen and (max-width: 768px) {

    .front-card,
    .back-card {
        position: absolute;
        width: 248px;
        height: 136px;
        margin-left: 0;

    }

    .front-card {
        bottom: -2rem;
        left: 1rem;
        z-index: 10;

        .card-number {
            font-size: 1rem;
        }

        .cardholder-name {
            font-size: 0.8rem;
        }

        .exp-date {
            font-size: 0.8rem;
        }
    }

    .back-card {
        top: 2rem;
        right: 1rem;

        p {
            margin-right: 2rem;
            font-size: 0.8rem;
        }
    }
}

.credit-form {
    min-width: 150px;
    max-width: 400px;
    width: 100%;
}

.full-width {
    width: 100%;
}

form {
    width: 100%;
    display: flex;
    flex-direction: column;

    input::-webkit-outer-spin-button,
    input::-webkit-inner-spin-button {
        -webkit-appearance: none;
        margin: 0;
    }

    .card-infos-container {

        .date-container {
            width: 47%;

            .date {

                display: flex;
                gap: 1rem;
                width: 100%;

                mat-form-field {
                    width: 40%;
                }
            }
        }
    }

    button {
        height: fit-content;
    }
}

.button-form {
    margin-right: 10px;
    height: fit-content;
    font-size: larger;
}


.tp-box__side {
    width: 100%;
    height: 100%;
    position: absolute;

    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;

    color: #fff;
    text-align: center;
    line-height: 100px;
    font-size: 24px;
    font-weight: 700;
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

.tp-box {
    position: relative;
    height: 215px;
    z-index: 15;
    margin: 3rem auto;
    -webkit-transform-style: preserve-3d;
    transform-style: preserve-3d;
    -webkit-transform: transform 1s;
    -ms-transform: transform 1s;
    transform: transform 1s;
}

I hope this will be interesting......

See you on next one........

Here in the attached sample.