React

by alexb

HTML

<div id="root"></div>

CSS

html {
  box-sizing: border-box;
}

html * {
  box-sizing: inherit;
}

body {
  background: #ccb;
  font-family: Helvetica;
  margin: 0;
  padding: 54px;
}

.root {
  display: flex;
  justify-content: center;
}

.app {
  display: flex;
  align-items: center;
  flex-direction: column;
}

.payment-card {
  position: relative;
  width: 344px;
  height: 216px;
  perspective: 500px;
  transform-style: preserve-3d;
}

.payment-card .front,
.payment-card .back {
  border: 2px solid #000;
  border-radius: 12px;
  transition: transform 10s ease;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.payment-card .front {
  background: cornflowerblue;
}

.payment-card .back {
  background: firebrick;
  transform: translateZ(-1px) rotate3d(0, 1, 0, -180deg);
}

.payment-card_flipped .front {
  transform: translateZ(-1px) rotate3d(0, 1, 0, 180deg);
}

.payment-card_flipped .back {
  transform: none;
}

.payment-card .name {
  position: absolute;
  left: 5%;
  bottom: 5%;
}

.payment-card .number {
  position: absolute;
  left: 50%;
  bottom: 40%;
  transform: translateX(-50%);
}

.payment-card .expires {
  position: absolute;
  left: 50%;
  bottom: 25%;
  transform: translateX(-50%);
}

.payment-card .cvv {
  position: absolute;
  left: 50%;
  bottom: 40%;
  transform: translateX(-50%);
}

.fields {
  display: flex;
  flex-direction: column;
  margin-top: 2em;
  width: 344px;
}

label {
  display: flex;
  flex-direction: column;
}

.label-text {
  font-size: 0.75em;
  margin-bottom: 0.25em;
}

input {
  border: none;
  border-radius: 2px;
  font-size: 16px;
  margin-bottom: 0.5em;
  padding: 0.5em;
}

input:focus {
  outline: none;
}

React

const PaymentCard = ({ className, name, number, expires, cvv }) => (
  <div className={`payment-card ${className}`}>
    <div className="front">
      <span className="name">{name}</span>
      <span className="number">{number}</span>
      <span className="expires">{expires}</span>
    </div>
    <div className="back">
      <span className="cvv">{cvv}</span>
    </div>
  </div>
);

const Field = ({ label, ...props }) => (
	<label>
    <span className="label-text">{label}</span>
	  <input {...props} />
	</label>
)

const App = () => {
	const [showBackOfCard, setShowBackOfCard] = React.useState(false);
  
  const cardDetails = {
  	name: 'Mr A Barrett',
    number: '4242 4242 4242 4242',
    expires: '11/22',
    cvv: '369'
  }
  
	return (
  	<div className="app">
      <PaymentCard
        className={showBackOfCard ? 'payment-card_flipped' : ''}
        {...cardDetails}
      />
      <div className="fields">
        <Field label="Name on card" value={cardDetails.name} />
        <Field label="Card number" value={cardDetails.number} />
        <Field label="Expiry date" value={cardDetails.expires} />
        <Field
          label="Security code"
          value={cardDetails.cvv}
          onFocus={() => setShowBackOfCard(true)}
          onBlur={() => setShowBackOfCard(false)}
        />
      </div>
    </div>
  );
};

ReactDOM.render(<App />, document.querySelector("#root"))