Open demo

CSS code

HTML
<div class="lf">
<main class="lf-box">
  <div class="lf-mark" aria-hidden="true">N</div>
  <h1>Sign in with your phone</h1>
  <p class="lf-sub">We'll text you a one-time code. No password needed.</p>
  <form onsubmit="event.preventDefault()">
    <label class="lf-label" for="tel">Mobile number</label>
    <div class="lf-tel">
      <select name="country_code" aria-label="Country calling code" autocomplete="tel-country-code">
        <option value="+44">๐Ÿ‡ฌ๐Ÿ‡ง +44</option><option value="+1">๐Ÿ‡บ๐Ÿ‡ธ +1</option><option value="+49">๐Ÿ‡ฉ๐Ÿ‡ช +49</option>
        <option value="+91">๐Ÿ‡ฎ๐Ÿ‡ณ +91</option><option value="+61">๐Ÿ‡ฆ๐Ÿ‡บ +61</option>
      </select>
      <input id="tel" name="phone" type="tel" inputmode="tel" autocomplete="tel-national"
             placeholder="7700 900123" required>
    </div>
    <p class="lf-legal">Message and data rates may apply. By continuing you agree to our
      <a href="#">Terms</a> and <a href="#">Privacy Policy</a>.</p>
    <button class="lf-btn" type="submit">Send code</button>
  </form>
  <div class="lf-or"><span>or</span></div>
  <button class="lf-alt" type="button">Sign in with email instead</button>
</main>
</div>
CSS
/* Phone login: a calling-code select and a national number joined into one field, then "Send code".
   autocomplete="tel-country-code" and "tel-national" let the browser fill both halves. */
.lf{--lf-brand:#4f46e5;--lf-brand-dark:#4338ca;--lf-ink:#111827;--lf-muted:#6b7280;--lf-line:#e5e7eb;--lf-edge:#868c99;--lf-bg:#f5f6fa;
  min-height:100vh;display:grid;grid-template-columns:minmax(0,1fr);place-items:center;padding:28px 20px;
  background:var(--lf-bg);color:var(--lf-ink);line-height:normal;
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
.lf,.lf *,.lf *::before,.lf *::after{box-sizing:border-box}
.lf :where(h1,p,form){margin:0}
.lf :where(input,select,button){font:inherit}
.lf a{color:var(--lf-brand);text-decoration:none;font-weight:600}
.lf a:hover{text-decoration:underline}
.lf :focus-visible{outline:2px solid var(--lf-brand);outline-offset:2px}
.lf-box{width:100%;max-width:410px;background:#fff;border:1px solid var(--lf-line);border-radius:16px;
  padding:38px 34px;box-shadow:0 10px 34px rgba(17,24,39,.06)}
.lf-mark{width:42px;height:42px;border-radius:12px;background:var(--lf-brand);display:grid;place-items:center;
  color:#fff;font-weight:800;margin-bottom:22px}
.lf h1{font-size:1.4rem;letter-spacing:-.02em;margin-bottom:7px}
.lf-sub{color:var(--lf-muted);font-size:.93rem;line-height:1.6;margin-bottom:26px}
.lf-label{display:block;font-size:.85rem;font-weight:600;margin-bottom:6px}
.lf-tel{display:flex;border:1px solid var(--lf-edge);border-radius:10px;overflow:hidden;background:#fff;
  transition:border-color .15s,box-shadow .15s}
.lf-tel:focus-within{border-color:var(--lf-brand);box-shadow:0 0 0 3px rgba(79,70,229,.15)}
.lf-tel select{border:0;background:var(--lf-bg);padding:12px 8px 12px 12px;font-size:.93rem;cursor:pointer;color:inherit;
  border-right:1px solid var(--lf-line);max-width:118px}
.lf-tel select:focus{outline:none}
.lf-tel input{flex:1;min-width:0;border:0;padding:12px 14px;font-size:.95rem;color:inherit;background:none}
.lf-tel input::placeholder{color:var(--lf-muted)}
.lf-tel input:focus{outline:none}
.lf-legal{font-size:.8rem;color:var(--lf-muted);line-height:1.6;margin:16px 0 20px}
.lf-btn{width:100%;padding:13px;border:0;border-radius:10px;background:var(--lf-brand);color:#fff;
  font-size:.97rem;font-weight:700;cursor:pointer;transition:background .15s}
.lf-btn:hover{background:var(--lf-brand-dark)}
.lf-or{display:flex;align-items:center;gap:14px;margin:26px 0;color:var(--lf-muted);font-size:.8rem;
  letter-spacing:.08em;text-transform:uppercase}
.lf-or::before,.lf-or::after{content:"";flex:1;height:1px;background:var(--lf-line)}
.lf-alt{width:100%;padding:12px;border:1px solid var(--lf-line);border-radius:10px;background:#fff;
  font-size:.93rem;font-weight:600;color:var(--lf-ink);cursor:pointer;transition:background .15s}
.lf-alt:hover{background:var(--lf-bg)}
@media (prefers-reduced-motion:reduce){.lf-tel,.lf-btn,.lf-alt{transition:none}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div class="lf d-grid">
<main class="card w-100">
  <div class="card-body">
    <div class="lf-mark" aria-hidden="true">N</div>
    <h1>Sign in with your phone</h1>
    <p class="lf-sub text-body-secondary">We'll text you a one-time code. No password needed.</p>
    <form onsubmit="event.preventDefault()">
      <label class="form-label" for="tel">Mobile number</label>
      <div class="input-group flex-nowrap">
        <select class="form-select" name="country_code" aria-label="Country calling code" autocomplete="tel-country-code">
          <option value="+44">๐Ÿ‡ฌ๐Ÿ‡ง +44</option><option value="+1">๐Ÿ‡บ๐Ÿ‡ธ +1</option><option value="+49">๐Ÿ‡ฉ๐Ÿ‡ช +49</option>
          <option value="+91">๐Ÿ‡ฎ๐Ÿ‡ณ +91</option><option value="+61">๐Ÿ‡ฆ๐Ÿ‡บ +61</option>
        </select>
        <input class="form-control" id="tel" name="phone" type="tel" inputmode="tel" autocomplete="tel-national"
               placeholder="7700 900123" required>
      </div>
      <p class="lf-legal text-body-secondary">Message and data rates may apply. By continuing you agree to our
        <a href="#">Terms</a> and <a href="#">Privacy Policy</a>.</p>
      <button class="btn btn-brand w-100" type="submit">Send code</button>
    </form>
    <div class="lf-or d-flex align-items-center text-body-secondary text-uppercase"><span>or</span></div>
    <button class="btn btn-alt w-100" type="button">Sign in with email instead</button>
  </div>
</main>
</div>
CSS
/* Bootstrap .card, .input-group with .form-select and .form-control, and .btn, recoloured through Bootstrap's CSS variables.
   The whole .input-group takes the focus ring, so the calling code and number read as one field. */
.lf{--lf-brand:#4f46e5;--lf-brand-dark:#4338ca;--lf-ink:#111827;--lf-muted:#6b7280;--lf-line:#e5e7eb;--lf-edge:#868c99;
  --bs-body-color:var(--lf-ink);--bs-secondary-color:var(--lf-muted);--bs-border-color:var(--lf-edge);
  --bs-link-color-rgb:79,70,229;--bs-link-hover-color-rgb:67,56,202;
  min-height:100vh;grid-template-columns:minmax(0,1fr);place-items:center;padding:28px 20px;
  background:#f5f6fa;color:var(--lf-ink);line-height:normal}
.lf a{font-weight:600;text-decoration:none}
.lf a:hover{text-decoration:underline}
.lf :focus-visible{outline:2px solid var(--lf-brand);outline-offset:2px}
.lf .card{--bs-card-border-color:var(--lf-line);--bs-card-border-radius:16px;--bs-card-spacer-y:38px;--bs-card-spacer-x:34px;
  max-width:410px;box-shadow:0 10px 34px rgba(17,24,39,.06)}
.lf-mark{width:42px;height:42px;border-radius:12px;background:var(--lf-brand);display:grid;place-items:center;
  color:#fff;font-weight:800;margin-bottom:22px}
.lf h1{font-size:1.4rem;font-weight:700;line-height:normal;letter-spacing:-.02em;margin-bottom:7px}
.lf-sub{font-size:.93rem;line-height:1.6;margin-bottom:26px}
.lf .form-label{font-size:.85rem;font-weight:600;margin-bottom:6px}
.lf .input-group{border-radius:10px;transition:box-shadow .15s}
.lf .input-group:focus-within{box-shadow:0 0 0 3px rgba(79,70,229,.15)}
.lf .input-group:focus-within>*{border-color:var(--lf-brand)}
.lf .input-group .form-select{flex:0 0 auto;width:auto;max-width:118px;padding:12px 30px 12px 12px;background-position:right 10px center;
  background-color:#f5f6fa;font-size:.93rem;line-height:normal;border-right:1px solid var(--lf-line);border-radius:10px 0 0 10px;cursor:pointer}
.lf .input-group .form-control{padding:12px 14px;font-size:.95rem;line-height:normal;border-left:0;border-radius:0 10px 10px 0;margin-left:0!important}
.lf .input-group .form-control::placeholder{color:var(--lf-muted)}
.lf .input-group .form-select:focus,.lf .input-group .form-control:focus{box-shadow:none;outline:none}
.lf .input-group:focus-within .form-select{border-right-color:var(--lf-line)}
.lf-legal{font-size:.8rem;line-height:1.6;margin:16px 0 20px}
.lf .btn{--bs-btn-line-height:normal;--bs-btn-focus-box-shadow:none;transition:background-color .15s}
.lf .btn-brand{--bs-btn-border-width:0;--bs-btn-padding-y:13px;--bs-btn-font-size:.97rem;--bs-btn-font-weight:700;--bs-btn-border-radius:10px;
  --bs-btn-bg:var(--lf-brand);--bs-btn-border-color:var(--lf-brand);--bs-btn-color:#fff;
  --bs-btn-hover-bg:var(--lf-brand-dark);--bs-btn-hover-border-color:var(--lf-brand-dark);--bs-btn-hover-color:#fff;
  --bs-btn-active-bg:var(--lf-brand-dark);--bs-btn-active-border-color:var(--lf-brand-dark);--bs-btn-active-color:#fff}
.lf .btn-alt{--bs-btn-padding-y:12px;--bs-btn-font-size:.93rem;--bs-btn-font-weight:600;--bs-btn-border-radius:10px;
  --bs-btn-bg:#fff;--bs-btn-border-color:var(--lf-line);--bs-btn-color:var(--lf-ink);
  --bs-btn-hover-bg:#f5f6fa;--bs-btn-hover-border-color:var(--lf-line);--bs-btn-hover-color:var(--lf-ink);
  --bs-btn-active-bg:#f5f6fa;--bs-btn-active-border-color:var(--lf-line);--bs-btn-active-color:var(--lf-ink)}
.lf-or{gap:14px;margin:26px 0;font-size:.8rem;letter-spacing:.08em}
.lf-or::before,.lf-or::after{content:"";flex:1;height:1px;background:var(--lf-line)}
@media (prefers-reduced-motion:reduce){.lf .input-group,.lf .btn{transition:none}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div class="grid min-h-screen grid-cols-[minmax(0,1fr)] place-items-center bg-page px-5 py-7 font-[-apple-system,BlinkMacSystemFont,'Segoe_UI',Roboto,Helvetica,Arial,sans-serif] leading-[normal] text-ink">
<main class="w-full max-w-[410px] rounded-2xl border border-line bg-white px-[34px] py-[38px] shadow-[0_10px_34px_rgba(17,24,39,.06)]">
  <div class="mb-[22px] grid size-[42px] place-items-center rounded-xl bg-brand font-extrabold text-white" aria-hidden="true">N</div>
  <h1 class="mb-[7px] text-[1.4rem] font-bold tracking-[-.02em]">Sign in with your phone</h1>
  <p class="mb-[26px] text-[.93rem] leading-[1.6] text-muted">We'll text you a one-time code. No password needed.</p>
  <form onsubmit="event.preventDefault()">
    <label class="mb-1.5 block text-[.85rem] font-semibold" for="tel">Mobile number</label>
    <div class="flex overflow-hidden rounded-[10px] border border-edge bg-white transition-[border-color,box-shadow] duration-150 focus-within:border-brand focus-within:shadow-[0_0_0_3px_rgba(79,70,229,.15)] motion-reduce:transition-none">
      <select class="max-w-[118px] cursor-pointer appearance-auto border-0 border-r border-line bg-page py-3 pr-2 pl-3 text-[.93rem] focus:outline-none" name="country_code" aria-label="Country calling code" autocomplete="tel-country-code">
        <option value="+44">๐Ÿ‡ฌ๐Ÿ‡ง +44</option><option value="+1">๐Ÿ‡บ๐Ÿ‡ธ +1</option><option value="+49">๐Ÿ‡ฉ๐Ÿ‡ช +49</option>
        <option value="+91">๐Ÿ‡ฎ๐Ÿ‡ณ +91</option><option value="+61">๐Ÿ‡ฆ๐Ÿ‡บ +61</option>
      </select>
      <input class="min-w-0 flex-1 border-0 bg-transparent px-3.5 py-3 text-[.95rem] placeholder:text-muted focus:outline-none"
             id="tel" name="phone" type="tel" inputmode="tel" autocomplete="tel-national" placeholder="7700 900123" required>
    </div>
    <p class="mt-4 mb-5 text-[.8rem] leading-[1.6] text-muted">Message and data rates may apply. By continuing you agree to our
      <a class="font-semibold text-brand hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand" href="#">Terms</a> and <a class="font-semibold text-brand hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand" href="#">Privacy Policy</a>.</p>
    <button class="w-full cursor-pointer rounded-[10px] bg-brand p-[13px] text-[.97rem] font-bold text-white transition-[background-color,border-color,color] duration-150 hover:bg-brand-dark focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand motion-reduce:transition-none" type="submit">Send code</button>
  </form>
  <div class="my-[26px] flex items-center gap-3.5 text-[.8rem] tracking-[.08em] text-muted uppercase before:h-px before:flex-1 before:bg-line after:h-px after:flex-1 after:bg-line"><span>or</span></div>
  <button class="w-full cursor-pointer rounded-[10px] border border-line bg-white p-3 text-[.93rem] font-semibold text-ink transition-[background-color,border-color,color] duration-150 hover:bg-page focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand motion-reduce:transition-none" type="button">Sign in with email instead</button>
</main>
</div>
CSS
@theme {
  --color-brand: #4f46e5;
  --color-brand-dark: #4338ca;
  --color-ink: #111827;
  --color-muted: #6b7280;
  --color-line: #e5e7eb;
  --color-edge: #868c99;
  --color-page: #f5f6fa;
}

About this set

A passwordless login that sends a one-time code by text message. The card asks for a mobile number in one combined field: a country calling-code select with flags on the left and the national number on the right, sharing a single border and focus ring. A small legal line about message rates links to the terms and privacy policy, a Send code button submits, and an or divider leads to a Sign in with email instead button. Use it for consumer apps where phone numbers are the primary identifier, or as the first half of a flow that continues with a one-time-code screen. Both halves carry autocomplete tokens, tel-country-code on the select and tel-national on the input, so browsers can fill them from a saved phone number, and the input uses type=”tel” for the phone keypad. The Bootstrap version builds the field from .input-group, .form-select and .form-control, with the focus ring moved to the group; the Tailwind version uses a flex row with focus-within utilities.

Whatโ€™s included

  • Calling-code select and number joined into one field
  • autocomplete="tel-country-code" and "tel-national"
  • type="tel" for the numeric phone keypad
  • Legal line with terms and privacy links above the button
  • Email fallback button under an or divider

Accessibility

The number input has the visible label Mobile number and the select is named Country calling code. The joined field shows a brand ring whenever either part has focus, and buttons and links get a 2px outline. Border and focus transitions are removed under prefers-reduced-motion.

Customise it

Edit the option list for your countries. Colours are --lf-brand, --lf-edge and --lf-bg on .lf (plain CSS and Bootstrap) or the --color-* theme values (Tailwind); the select's width is capped at 118px.