সরাসরি পর্বে যান
পর্ব ০৯ · ৫৯-এর মধ্যে · মডিউল ২

ফর্মের নানা কন্ট্রোল আর built-in validation

Form Controls & Built-in Validation — checkbox, radio, select, datalist, date, range, file, meter, required, pattern & the Constraint Validation API

Taught in Bangla, this lesson covers form controls and built-in validation: checkbox versus radio, select, optgroup, textarea and datalist, newer input types such as date, range, color and file, and output, progress and meter. It explains required, min, max, minlength and pattern with a Bangladeshi mobile number regex, novalidate, disabled versus readonly, setCustomValidity, and why servers must validate again.

এই পর্বে যা শিখবেন

  • checkbox, radio, select, optgroup, textarea আর datalist — কোনটা কখন, আর জমা দিলে আসলে কী পাঠানো হয়
  • date, time, datetime-local, month, range, color, file, search, url, hidden — আর output, progress, meter
  • ব্রাউজারের built-in validation কীভাবে কাজ করে, আর বাংলাদেশি মোবাইল নম্বর দিয়ে pattern-এর regex সহজে পড়া
  • :invalid, :user-invalid, novalidate, formnovalidate, disabled বনাম readonly আর setCustomValidity
  • কেন ক্লায়েন্টের যাচাই নিরাপত্তা নয়, আর AI-এর বানানো ফর্ম কীভাবে যাচাই করবেন

১ · ফর্ম একটি কথোপকথন — প্রশ্নের ধরন দেখে কন্ট্রোল

ব্যাংকে হিসাব খুলতে গেলে একটি ছাপা ফর্ম পূরণ করতে হয়। খেয়াল করলে দেখবেন, ফর্মের প্রতিটি প্রশ্নের উত্তর দেওয়ার ধরন আলাদা। নামের জন্য ফাঁকা লাইন। “হিসাবের ধরন”-এর পাশে তিনটি গোল ঘর — সঞ্চয়ী, চলতি, স্থায়ী — যেকোনো একটিতে টিক। “কোন কোন সেবা চান” — এটিএম কার্ড, SMS, ইন্টারনেট ব্যাংকিং — যতগুলো খুশি চৌকো ঘরে টিক। আর নিচে “ঠিকানা” লেখার জন্য কয়েক লাইনের বড় জায়গা।

যিনি ফর্মটি ছাপিয়েছেন, তিনি প্রতিটি প্রশ্নের জন্য ভেবেচিন্তে উত্তরের ঘর বেছেছেন। ঘর ঠিক থাকলে ভুল কম হয়, পূরণ করতে সময় কম লাগে। ওয়েবের ফর্মেও ঠিক তাই। পর্ব ০৮-এ আপনি ফর্মের ভিত্তি দেখেছেন — <form>, <input>, <label> আর <button>. এই পর্বে দেখবেন উত্তরের ঘরের পুরো ভাণ্ডার, যাদের একসাথে বলে form control, আর দেখবেন ব্রাউজার কীভাবে নিজেই উত্তর যাচাই করে।

প্রশ্নের ধরনউদাহরণঠিক কন্ট্রোল
অনেকগুলোর মধ্যে যতগুলো খুশিআগ্রহের বিষয়, চাই এমন সেবাtype="checkbox"
কয়েকটির মধ্যে ঠিক একটি (সব চোখের সামনে)পেমেন্টের উপায়, ক্লাসের শিফটtype="radio"
লম্বা তালিকা থেকে একটি বা কয়েকটি৬৪টি জেলার একটি<select>
মুক্ত লেখা, কিন্তু কিছু পরামর্শ সহব্যাংকের নাম, শহরের নাম<input list> + <datalist>
কয়েক লাইনের লেখাঠিকানা, মতামত<textarea>
তারিখ, সময়, পরিমাণ, রং, ফাইলজন্মতারিখ, ভলিউম, সার্টিফিকেটের স্ক্যানdate, range, color, file…
মূল ধারণা

ঠিক কন্ট্রোল বাছলে তিনটি জিনিস বিনামূল্যে পাওয়া যায়: চেহারা ও আচরণ (ক্যালেন্ডার, স্লাইডার, ফোনে সংখ্যার কি-বোর্ড), অর্থ (screen reader বলে “চেকবক্স, টিক দেওয়া নেই” বা “রেডিও বাটন, ৩টির ২য়”), আর যাচাই (ভুল তারিখ বা ভুল ইমেইল ব্রাউজার নিজেই আটকায়)। নিজে div আর JavaScript দিয়ে এসব বানালে এই তিনটিই হাতে বানাতে হয় — আর প্রায় সবসময় কিছু না কিছু বাদ পড়ে।

২ · checkbox আর radio — “যত খুশি” বনাম “শুধু একটি”

Checkbox একটি চৌকো ঘর, যার দুটি অবস্থা — টিক আছে, টিক নেই। প্রতিটি checkbox নিজে স্বাধীন; একটিতে টিক দিলে অন্যটির কিছু হয় না। Radio button গোল ঘর, আর এরা সবসময় দলে থাকে: দলের একটি বাছলে আগেরটি নিজে থেকে উঠে যায়। নামটা এসেছে পুরোনো রেডিওর স্টেশন-বোতাম থেকে — একটি চাপলে আগেরটি লাফ দিয়ে উঠে আসত।

ব্রাউজার কীভাবে বোঝে কোন radio-গুলো এক দলের? একই name দেখে। এটাই এই অংশের সবচেয়ে জরুরি নিয়ম। আরও তিনটি জিনিস মনে রাখুন:

  • value — জমা দিলে সার্ভারে কোন মান যাবে। পর্দায় লেখা থাকে “বিকাশ”, কিন্তু পাঠানো হয় value="bkash" — সার্ভারের জন্য ইংরেজি ছোট কোড সুবিধাজনক। checkbox-এ value না দিলে ব্রাউজার পাঠায় on.
  • checked — একটি boolean attribute; পাতা খোলার সময় কোনটিতে আগে থেকেই টিক থাকবে।
  • টিক না দেওয়া checkbox কিছুই পাঠায় না — না নাম, না মান। সার্ভার “না” শোনে না, কিছুই শোনে না। তাই সার্ভারে “না পেলে মানে না” ধরে নিতে হয়।

একদল radio বা সম্পর্কিত checkbox-কে মুড়ে দিন <fieldset> দিয়ে, আর দলের প্রশ্নটি লিখুন তার প্রথম সন্তান <legend>-এ। তাহলে screen reader প্রতিটি বোতামের আগে প্রশ্নটিও শোনায় — “ক্লাসের সময়, দল; সকাল, রেডিও বাটন, ৩টির ১ম”. শুধু “সকাল” শুনলে শ্রোতা বুঝতেন না প্রশ্নটা কী ছিল।

<form>
  <fieldset>
    <legend>কোন কোন কোর্সে আগ্রহী? (যত খুশি)</legend>
    <label><input type="checkbox" name="course" value="html" checked> HTML ও CSS</label><br>
    <label><input type="checkbox" name="course" value="js"> JavaScript</label><br>
    <label><input type="checkbox" name="course" value="python"> Python</label>
  </fieldset>
  <fieldset>
    <legend>ক্লাসের সময় (শুধু একটি)</legend>
    <label><input type="radio" name="shift" value="morning" checked> সকাল</label>
    <label><input type="radio" name="shift" value="evening"> সন্ধ্যা</label>
    <label><input type="radio" name="shift" value="weekend"> শুক্র-শনি</label>
  </fieldset>
  <p><label><input type="checkbox" name="sms"> SMS-এ খবর চাই</label></p>
  <button>জমা দিন</button>
</form>

দুটি ফ্রেম-ঘেরা দল দেখবেন — fieldset-এর ডিফল্ট দাগ, আর দাগের ওপর legend-এর লেখা। “জমা দিন” চাপলে নিচে আসবে course=html&shift=morning. আরও দুটি কোর্সে টিক দিয়ে আবার চাপুন — course নামটা তিনবার আসবে, প্রতিটি নিজের মান নিয়ে। sms আসে না, যতক্ষণ না টিক দেন; টিক দিলে আসে sms=on, কারণ তার কোনো value নেই। চেষ্টা করুন: “সন্ধ্যা”-র name বদলে shift2 করুন — এখন সকাল আর সন্ধ্যা দুটোই একসাথে বাছা যায়, কারণ তারা আর এক দলের নয়। আর লেবেলের লেখায় (যেমন “সকাল” শব্দে) ক্লিক করে দেখুন — label থাকায় ছোট গোল ঘরটিতে নিশানা করতে হয় না।

দুটি প্রচলিত ভুল। এক, একটিমাত্র “হ্যাঁ/না” প্রশ্নে দুটি radio (“হ্যাঁ”, “না”) না দিয়ে একটি checkbox-ই যথেষ্ট — “শর্তাবলি মানছি”. দুই, radio দলে কোনোটিতে আগে থেকে checked না দিলে, একবার বাছার পর ব্যবহারকারী আর “কিছুই না বাছা” অবস্থায় ফিরতে পারেন না — radio-কে আনচেক করা যায় না। তাই সম্ভব হলে একটি যুক্তিসংগত ডিফল্ট দিন, অথবা “বলতে চাই না” ধরনের একটি বিকল্প রাখুন।

৩ · select, optgroup, textarea আর datalist

select — লম্বা তালিকার ড্রপডাউন

৬৪টি জেলার জন্য ৬৪টি radio বসালে পাতা ভরে যাবে। তখন <select> — ক্লিক করলে খোলে এমন একটি তালিকা, যার প্রতিটি বিকল্প একটি <option>. বিকল্পগুলোকে দলে ভাগ করতে <optgroup label="ঢাকা বিভাগ"> — দলের নামটি নিজে বাছা যায় না, শুধু শিরোনাম হিসেবে দেখায়।

  • <option>-এ value না দিলে তার ভেতরের লেখাটাই মান হয়ে যায়।
  • selected — কোনটি আগে থেকে বাছা থাকবে। না দিলে প্রথমটি।
  • multiple — একাধিক বাছাই (কম্পিউটারে Ctrl বা ⌘ চেপে ক্লিক)। তখন ড্রপডাউন না হয়ে খোলা একটি বাক্স দেখায়; size বলে কয়টি সারি দেখা যাবে। Ctrl চেপে বাছার কথা অনেকে জানেন না, তাই অল্প বিকল্পে checkbox-এর দল প্রায়ই ভালো।
  • প্রথম বিকল্প <option value="">— বেছে নিন —</option> আর select-এ required দিলে, কেউ কিছু না বেছে জমা দিতে পারবেন না। এটাই select-এর “placeholder”.

textarea — কয়েক লাইনের লেখা

<textarea> হলো বড় লেখার ঘর — ঠিকানা, মতামত, অভিযোগ। এর দুটি অদ্ভুত স্বভাব আছে। এটা <input>-এর মতো খালি (void) element নয়, তাই </textarea> বন্ধ করতেই হয়। আর এর value attribute নেই — শুরুর লেখা বসে খোলা আর বন্ধ ট্যাগের মাঝখানে, এবং সেখানে ফাঁকা জায়গা আর নতুন লাইন যেমন লেখেন হুবহু তেমন থাকে। তাই <textarea> আর </textarea>-এর মাঝে কোড সুন্দর দেখাতে indent দিলে সেই ফাঁকাগুলোও ঘরের ভেতরে ঢুকে যায়। rows আর cols শুরুর মাপ বলে (CSS দিয়েও দেওয়া যায়)।

datalist — পরামর্শ দেয়, জোর করে না

কখনো চান ব্যবহারকারী যা খুশি লিখুন, কিন্তু সাধারণ উত্তরগুলো পরামর্শ হিসেবে দেখুক — যেমন ব্যাংকের নাম। তখন একটি সাধারণ input-এ list="banks" দিন, আর id="banks" দেওয়া একটি <datalist>-এ বিকল্পগুলো রাখুন। লিখতে শুরু করলে মিলে যাওয়া পরামর্শ ভেসে ওঠে, কিন্তু তালিকার বাইরের নামও লেখা যায়। select-এর সাথে এটাই পার্থক্য — select-এ তালিকার বাইরে কিছু বাছা যায় না।

<form>
  <label for="dist">জেলা</label>
  <select id="dist" name="district" required>
    <option value="">— বেছে নিন —</option>
    <optgroup label="ঢাকা বিভাগ">
      <option value="dhaka">ঢাকা</option>
      <option value="gazipur">গাজীপুর</option>
    </optgroup>
    <optgroup label="চট্টগ্রাম বিভাগ">
      <option value="ctg">চট্টগ্রাম</option>
      <option value="cox">কক্সবাজার</option>
    </optgroup>
  </select>
  <p><label for="skills">দক্ষতা (Ctrl চেপে একাধিক)</label><br>
  <select id="skills" name="skill" multiple size="3">
    <option selected>HTML</option><option>CSS</option><option selected>Figma</option>
  </select></p>
  <p><label for="bank">ব্যাংক</label> <input id="bank" name="bank" list="banks">
  <datalist id="banks">
    <option value="সোনালী ব্যাংক"></option><option value="জনতা ব্যাংক"></option><option value="ব্র্যাক ব্যাংক"></option>
  </datalist></p>
  <p><label for="addr">ঠিকানা</label><br>
  <textarea id="addr" name="address" rows="3" cols="30">বাড়ি ১২, রোড ৫</textarea></p>
  <button>জমা দিন</button>
</form>

কিছু না বেছে “জমা দিন” চাপুন — জেলার ঘরে ব্রাউজারের নিজের সতর্কবার্তা আসবে, কারণ প্রথম বিকল্পের মান ফাঁকা আর select-এ required আছে। জেলা বেছে আবার চাপলে দেখবেন skill=HTML&skill=Figma — একাধিক বাছাই মানে একই নাম কয়েকবার; value না থাকায় লেখাটাই মান। ব্যাংকের ঘরে “ব্যা” বা “জ” লিখুন (বা ঘরে দুবার ক্লিক করুন) — পরামর্শ ভেসে উঠবে; চাইলে তালিকার বাইরের নামও লিখতে পারবেন। চেষ্টা করুন: textarea-র শুরুর লেখার আগে কয়েকটি space আর একটি নতুন লাইন বসান — প্রিভিউতে সেগুলোও ঘরের ভেতরে দেখা যাবে। (datalist-এর চেহারা ব্রাউজার ভেদে বেশ আলাদা।)

সমর্থনের কথা: select, optgroup আর textarea বহু বছর ধরে সব ব্রাউজারে চলে। datalist-ও সব প্রধান ব্রাউজারে আছে, কিন্তু পরামর্শ দেখানোর ধরন ব্রাউজার ও ফোন ভেদে আলাদা — একে “থাকলে ভালো” সুবিধা ভাবুন; না দেখালেও ঘরটা সাধারণ input হিসেবে কাজ করে। select-এর ড্রপডাউন পুরো সাজানোর নতুন “customizable select” (appearance: base-select) এখনো Baseline নয় — সব প্রধান ব্রাউজারে আসছে, ব্যবহারের আগে Can I use দেখে নিন; ফর্ম সাজানো পর্ব ৪৩-এ।

৪ · নতুন input type — date, range, color, file আর আরও

পর্ব ০৮-এ দেখেছেন <input>-এর type বদলালে একই ট্যাগ ভিন্ন জিনিস হয়ে যায়। HTML5-এর সময় (২০১০-এর দশকের শুরুতে ব্রাউজারে আসতে শুরু করে) একঝাঁক নতুন input type যোগ হয়। আগে তারিখ নিতে মানুষ তিনটি select (দিন, মাস, বছর) বা ভারী JavaScript ক্যালেন্ডার লাইব্রেরি ব্যবহার করতেন; এখন এক লাইনেই হয়।

typeকী নেয়জমা হওয়া মানের রূপসমর্থন
dateতারিখ, ক্যালেন্ডার থেকে2005-03-26Widely available
timeসময়09:30Widely available
datetime-localতারিখ + সময় (সময় অঞ্চল ছাড়া)2026-11-01T10:00Widely available
monthমাস ও বছর2026-10Baseline নয় — কিছু ব্রাউজারে সাধারণ টেক্সট বক্স
rangeএকটি সীমার মধ্যে মোটামুটি মান, স্লাইডারে7Widely available
colorরং#006a4eWidely available
fileএক বা একাধিক ফাইলফাইলের আধেয় (সাথে নাম)Widely available
searchখোঁজার লেখাসাধারণ লেখাWidely available
url, email, telঠিকানা, ইমেইল, ফোনসাধারণ লেখাWidely available
hiddenকিছুই না — চোখে দেখা যায় নাআপনার বসানো মানসবখানে

কয়েকটির বিশেষ কথা আছে:

  • তারিখের চেহারা আর মান আলাদা। পর্দায় তারিখ দেখায় ব্যবহারকারীর দেশের নিয়মে (কারও কাছে ২৬/০৩/২০০৫, কারও কাছে 03/26/2005), কিন্তু সার্ভারে সবসময় যায় yyyy-mm-dd. তাই “দিন আগে না মাস আগে” নিয়ে সার্ভারের ঝগড়া নেই। min আর max-ও এই রূপেই লিখতে হয়।
  • range নির্ভুল সংখ্যার জন্য নয়। ভলিউম, উজ্জ্বলতা, “কতটা সন্তুষ্ট” — যেখানে মোটামুটি মানই যথেষ্ট। বয়স বা দাম নিতে range দিলে ঠিক সংখ্যায় থামানো কষ্টকর। ডিফল্ট সীমা min="0" থেকে max="100", আর স্লাইডার দেখায় না সংখ্যাটা কত — তাই পাশে মান দেখাতে <output> লাগে (পরের অংশে)।
  • file: type="file"-এ accept=".pdf,image/*" ফাইল বাছার জানালায় শুধু PDF আর ছবি দেখায়, multiple একাধিক ফাইল বাছতে দেয়। কিন্তু accept শুধু পরামর্শ — ব্যবহারকারী জানালায় “All files” বেছে যেকোনো ফাইল দিতে পারেন। ফাইল আসলেই পাঠাতে ফর্মে method="post" আর enctype="multipart/form-data" লাগে।
  • search দেখতে text-এর মতো, কিন্তু অনেক ব্রাউজারে লেখা মোছার ছোট “×” বোতাম দেয়, আর screen reader একে “search box” বলে।
  • hidden — type="hidden" পর্দায় কিছুই দেখায় না, কিন্তু মানটি চুপচাপ জমা হয় — যেমন “কোন বিজ্ঞাপন থেকে এসেছেন”. “লুকানো” মানে “গোপন” নয়; DevTools-এ যে কেউ দেখতে ও বদলাতে পারেন (অংশ ৯ দেখুন)।

ফোনে আরেকটি বড় লাভ: email-এ কি-বোর্ডে @ চলে আসে, tel-এ সংখ্যার প্যাড, url-এ “/” আর “.com”. ব্যবহারকারীকে কি-বোর্ড বদলাতে হয় না। শুধু কি-বোর্ড বদলাতে চাইলে, যাচাই ছাড়া, আছে inputmode attribute — যেমন inputmode="numeric".

<form oninput="vout.value = vol.value">
  <p><label>জন্মতারিখ <input type="date" name="dob" min="1960-01-01" value="2005-03-26"></label></p>
  <p><label>ক্লাসের সময় <input type="time" name="t" value="09:30"></label></p>
  <p><label>সাক্ষাৎকার <input type="datetime-local" name="iv"></label></p>
  <p><label>বিলের মাস <input type="month" name="bill"></label></p>
  <p><label>থিমের রং <input type="color" name="c" value="#006a4e"></label></p>
  <p><label for="vol">ভলিউম</label>
     <input type="range" id="vol" name="vol" min="0" max="10" value="7">
     <output id="vout" for="vol">7</output></p>
  <p><label>সার্টিফিকেট (PDF/ছবি) <input type="file" name="docs" accept=".pdf,image/*" multiple></label></p>
  <p><label>খুঁজুন <input type="search" name="q"></label></p>
  <input type="hidden" name="source" value="facebook-ad">
  <button>জমা দিন</button>
</form>

প্রতিটি ঘর আলাদা চেহারার: তারিখের পাশে ক্যালেন্ডারের চিহ্ন, সময়ের ঘর, রঙের ছোট বাক্স (বাংলাদেশের পতাকার সবুজ), স্লাইডার আর তার পাশে 7, ফাইল বাছার বোতাম। স্লাইডার টানুন — পাশের সংখ্যা সাথে সাথে বদলাবে। “জমা দিন” চাপুন — dob=2005-03-26 আসবে yyyy-mm-dd রূপে, আর শেষে source=facebook-ad, যদিও পর্দায় তার কোনো ঘর নেই। মাসের ঘরটি আপনার ব্রাউজারে সাধারণ টেক্সট বক্স হলে, সেটিই “Baseline নয়”-এর মানে। চেষ্টা করুন: জন্মতারিখে max="2010-12-31" যোগ করে ক্যালেন্ডার খুলুন — পরের তারিখগুলো বাছা যাবে না। আর value="#006a4e"-কে value="#f42a41" করুন — পতাকার লাল।

৫ · output, progress আর meter — ফল আর মাপ দেখানো

এ তিনটি element তথ্য নেয় না, দেখায়।

  • <output> — একটি হিসাবের ফল বা ব্যবহারকারীর কাজের ফল দেখানোর জায়গা: স্লাইডারের মান, “মোট দাম: ৳ ১২৫০”. for attribute-এ লিখে দিন কোন কোন ঘর থেকে ফলটি এসেছে। ওপরের এডিটরে <form oninput="…"> ছিল এক লাইনের JavaScript, যা প্রতিবার কোনো ঘর বদলালে output-এ মান বসায়।
  • <progress> — একটি কাজ কতদূর এগোল: ফাইল আপলোড ৬৫%, ধাপ ৩-এর ২. value না দিলে হয় “অনির্দিষ্ট” progress — শুধু বোঝায় “কাজ চলছে, কতক্ষণ জানি না”.
  • <meter> — একটি জানা সীমার মধ্যে মাপ: ফোনের চার্জ, স্টোরেজ কতটা ভরা, পাসওয়ার্ড কতটা শক্ত। low, high আর optimum বলে দেয় কোন অংশটা ভালো, আর ব্রাউজার সেই অনুযায়ী সবুজ, হলুদ বা লাল দেখায়।

পার্থক্যটা মনে রাখার উপায়: progress সময়ের সাথে শেষের দিকে এগোয়, meter একটি অবস্থা মাপে। ব্যাটারির চার্জ কোনো “কাজ” নয়, যা শেষ হবে — তাই সেটা meter.

<p><label for="up">ফাইল আপলোড:</label>
   <progress id="up" max="100" value="65">65%</progress> 65%</p>
<p><label for="wait">ফল প্রস্তুত হচ্ছে:</label>
   <progress id="wait"></progress></p>
<p><label for="bat">ফোনের চার্জ:</label>
   <meter id="bat" min="0" max="100" low="20" high="80" optimum="100" value="15">15%</meter> 15%</p>
<p><label for="pw">পাসওয়ার্ডের শক্তি:</label>
   <meter id="pw" min="0" max="4" low="1" high="3" optimum="4" value="2"></meter></p>
<p><label for="disk">স্টোরেজ ভরা:</label>
   <meter id="disk" min="0" max="64" low="40" high="56" optimum="0" value="30"></meter> 30 / 64 GB</p>

প্রথম দণ্ড দুই-তৃতীয়াংশ ভরা; দ্বিতীয়টি অনির্দিষ্ট (অনেক ব্রাউজারে একটি নড়তে থাকা দাগ)। ফোনের চার্জের meter লাল — ১৫ এসেছে “low”-এর নিচে, অথচ ভালো (optimum) হলো ওপরের দিক। পাসওয়ার্ডেরটি হলুদ — মাঝের অংশে। স্টোরেজেরটি সবুজ — এখানে optimum="0", অর্থাৎ কম ভরা থাকাই ভালো। চেষ্টা করুন: চার্জের value 15 থেকে 90 করুন — সবুজ হবে; স্টোরেজের value 60 করুন — লাল হবে। একই রং-নিয়ম, শুধু optimum কোন দিকে তার ওপর নির্ভর করে। (রং আর চেহারা ব্রাউজার ভেদে একটু আলাদা।)

পাশে লেখা কেন? শুধু রঙে তথ্য দেওয়া উচিত নয় — WCAG 2.2-এর ১.৪.১ (Use of Color) নিয়ম; অনেকে লাল-সবুজ আলাদা করতে পারেন না। তাই সংখ্যা বা শব্দেও লিখুন — “দুর্বল”, “মাঝারি”, “শক্ত”.

৬ · Built-in validation — ব্রাউজারের নিজের পরীক্ষক

ভর্তি পরীক্ষার আবেদন জমা নেওয়ার কাউন্টারের কথা ভাবুন। লোকটি ফর্ম হাতে নিয়েই দেখে নেন — ছবি আছে কি না, মোবাইলের ঘর ফাঁকা কি না। ভুল থাকলে সেখানেই ফেরত দেন: “এই ঘরটা পূরণ করুন।” এক সপ্তাহ পর চিঠিতে জানতে হয় না যে ফর্ম বাতিল।

ব্রাউজার ঠিক এই কাউন্টারের কাজটা করে, কোনো JavaScript ছাড়াই। একে বলে constraint validation — প্রতিটি ঘরের ওপর আপনি কিছু শর্ত (constraint) বসান, আর জমা দেওয়ার মুহূর্তে ব্রাউজার শর্তগুলো মিলিয়ে দেখে। শর্তগুলো attribute দিয়ে লেখা হয়:

Attributeশর্তকোথায় খাটে
requiredঘর ফাঁকা রাখা যাবে নাপ্রায় সব input, select, textarea
min, maxসবচেয়ে ছোট আর বড় মানnumber, range, date, time, month…
stepকত ধাপে ধাপে মান বাড়ে (ডিফল্ট 1)number, range, date, time…
minlength, maxlengthলেখার সবচেয়ে কম আর বেশি দৈর্ঘ্যtext, email, url, tel, password, search, textarea
patternলেখাটি একটি নকশার (regex) সাথে মিলতে হবেtext, tel, email, url, password, search
type="email", type="url"লেখাটি দেখতে ইমেইল বা পূর্ণ URL কি নানিজে নিজেই

কয়েকটি খুঁটিনাটি, যা নতুনদের প্রায়ই অবাক করে:

  • step-এর হিসাব শুরু হয় min থেকে। number-এ ডিফল্ট step হলো 1, তাই 2.5 লিখলে ব্রাউজার বলবে “নিকটতম বৈধ মান 2 বা 3”. দশমিক চাইলে step="0.5" বা যেকোনো মানের জন্য step="any". min="1" step="2" হলে বৈধ মান 1, 3, 5… — 4 নয়।
  • maxlength টাইপ করতেই দেয় না — সীমার পর আর অক্ষর ঢোকে না। কিন্তু minlength টাইপ আটকায় না, শুধু জমার সময় বলে “আরও লিখুন”.
  • type="email" শুধু দেখে লেখাটি “কিছু@কিছু” আকারের কি না — rahim@gmail-কেও বৈধ ধরে। ঠিকানাটি সত্যি আছে কি না, ব্রাউজার জানে না।
  • type="url" চায় scheme সহ পূর্ণ ঠিকানা: abcltech.com অবৈধ, https://abcltech.com বৈধ — তাই পাশে উদাহরণ দিন।
  • radio দলে একটিতে required দিলেই পুরো দল বাধ্যতামূলক। checkbox-এ required মানে “এই ঘরে টিক দিতেই হবে”; “কমপক্ষে একটি বাছুন” HTML একা পারে না (অংশ ৯)।
  • ফাঁকা ঘরে অন্য শর্ত খাটে না। required না থাকলে ফাঁকা ঘর বৈধ, pattern বা minlength যাচাই-ই হয় না; কিন্তু কিছু লিখলে ঠিকভাবে লিখতে হয়।

এবার দেখা যাক “জমা দিন” চাপার মুহূর্তে ব্রাউজারের ভেতরে ঠিক কী কী ঘটে। একটি চাকরির আবেদন ফর্ম ধরুন — নাম, মোবাইল, বয়স; মোবাইলের ঘরটি ভুল। “পরে” চাপুন:

  1. Submitbutton / Enterজমার অনুরোধ
  2. যাচাই চালু?novalidate?না থাকলে এগোয়
  3. প্রতিটি ঘরvalidityশর্ত মেলানো
  4. ভুল পেলেinvalidথামো, দেখাও
  5. সব ঠিকform dataসার্ভারে পাঠাও
  1. জমার অনুরোধ. submit বোতামে ক্লিক, বা কোনো লেখার ঘরে Enter চাপা — দুটোই একই কাজ শুরু করে। JavaScript-এর form.submit() কিন্তু এই যাচাই পুরোটা এড়িয়ে যায়; form.requestSubmit() যাচাইসহ জমা দেয়।
  2. যাচাই চালু কি না. <form novalidate> থাকলে, বা যে বোতামে চাপা হয়েছে তাতে formnovalidate থাকলে, ব্রাউজার সরাসরি ধাপ ৫-এ চলে যায়। (এ দুটির ব্যবহার অংশ ৮-এ।)
  3. প্রতিটি ঘর মেলানো. প্রতিটি কন্ট্রোলের একটি validity রিপোর্ট থাকে — valueMissing, typeMismatch, patternMismatch, tooShort, rangeOverflow, stepMismatch… কোনোটা সত্য হলে ঘরটি invalid. disabled, readonly আর hidden ঘর যাচাই থেকে বাদ পড়ে।
  4. ভুল পেলে থামা. প্রতিটি ভুল ঘরে একটি invalid ঘটনা ঘটে; তারপর ব্রাউজার প্রথম ভুল ঘরে focus নিয়ে যায় আর পাশে বার্তা দেখায় (বার্তা ব্রাউজারের ভাষায় — বাংলা ইন্টারফেসে বাংলায়)। জমা বাতিল; কোনো request যায় না, পাতাও বদলায় না।
  5. সব ঠিক হলে. এবার ব্রাউজার জমা দেওয়ার তালিকা বানায় — কোন ঘর পাঠানো হবে, কোনটা বাদ (অংশ ৮-এর স্টেপারে বিস্তারিত) — আর সার্ভারে একটি HTTP request পাঠায়। মনে রাখুন: সার্ভার জানে না এই যাচাই আদৌ হয়েছিল কি না।

২০০০-এর দশকের শুরুতে ফর্ম যাচাই মানেই ছিল নিজের লেখা JavaScript — প্রতিটি সাইট নিজের মতো করে “ঘর ফাঁকা কি না” পরীক্ষা লিখত। ২০০৪ সালের দিকে ব্রাউজার-নির্মাতাদের নতুন দল WHATWG “Web Forms 2.0” নামে একটি প্রস্তাব লেখা শুরু করে — required, pattern, min, max, আর date ও email-এর মতো নতুন type এসেছিল সেখান থেকেই। Opera ব্রাউজার সবার আগে এর বড় অংশ চালু করে। পরে প্রস্তাবটি HTML5-এর ভেতরে মিশে যায়, আর ২০১০-এর দশকে ধীরে ধীরে সব ব্রাউজারে আসে।

৭ · pattern — বাংলাদেশি মোবাইল নম্বর দিয়ে regex পড়া

বাংলাদেশের মোবাইল নম্বর দেখতে কেমন? ১১টি অঙ্ক; শুরু 01 দিয়ে; তৃতীয় অঙ্কটি অপারেটরের কোড, যা ৩ থেকে ৯-এর মধ্যে (013, 017, 018, 019…)। এই বর্ণনাকে যন্ত্রের ভাষায় লেখার উপায়ের নাম regular expression (সংক্ষেপে regex) — লেখার একটি “নকশা” বা ছাঁচ। আর pattern attribute-এ সেই ছাঁচটি লিখে দিলে ব্রাউজার মিলিয়ে দেখে:

<input type="tel" name="mobile" pattern="01[3-9][0-9]{8}"
       title="১১ অঙ্কের নম্বর, 01 দিয়ে শুরু — যেমন 01712345678">

প্রথম দেখায় অদ্ভুত চিহ্নের জঙ্গল মনে হয়। কিন্তু টুকরো টুকরো করে পড়লে খুবই সহজ। “পরে” চাপুন:

^(?: 01 [3-9] [0-9] {8} )$
  1. 01 — হুবহু অক্ষর. সাধারণ অক্ষর বা অঙ্ক regex-এ নিজেকেই বোঝায়। তাই লেখাটি শুরু হতে হবে ঠিক “0” তারপর “1” দিয়ে।
  2. [3-9] — একটি ঘর, কয়েকটি বিকল্প. বর্গ বন্ধনী মানে “এখানে এই তালিকার যেকোনো একটি অক্ষর”. 3-9 মানে ৩ থেকে ৯ পর্যন্ত। একে বলে character class. তৃতীয় অঙ্ক ০, ১ বা ২ হলে মিলবে না।
  3. [0-9] — যেকোনো একটি অঙ্ক. ০ থেকে ৯-এর যেকোনো একটি। (অনেকে লেখেন \d — একই কাজ।)
  4. {8} — ঠিক আটবার. ঠিক আগের টুকরোটি ([0-9]) কতবার আসবে — একে বলে quantifier. {8} মানে ঠিক ৮বার; {6,8} হলে ৬ থেকে ৮বার। হিসাব: 0, 1, অপারেটর কোড, আর ৮টি অঙ্ক = ১১।
  5. অদৃশ্য ^(?: … )$ — পুরো লেখাটাই মিলতে হবে. আপনি না লিখলেও ব্রাউজার আপনার pattern-কে এভাবে মুড়ে নেয়: ^ = শুরু, $ = শেষ। তাই লেখার একটি অংশ মিললে চলবে না, পুরোটা মিলতে হবে। +880 দিয়ে লেখা নম্বর বা মাঝে ড্যাশ দেওয়া নম্বর তাই অবৈধ।
  6. ফাঁকা ঘর আর space. ফাঁকা ঘরে pattern যাচাই হয় না — বাধ্যতামূলক করতে required লাগবে। আর মাঝে space থাকলে মিলবে না, কারণ space অঙ্ক নয়। কেউ +880 দিয়ে লিখতে চাইলে pattern হতে পারে (\+88)?01[3-9][0-9]{8} — ? মানে “আগের অংশটি থাকতেও পারে, না-ও পারে”.

title দিয়ে ইঙ্গিত দিন। pattern না মিললে ব্রাউজার বলে “অনুরোধ করা ফরম্যাট মেলান” — কোন ফরম্যাট, তা বলে না! অনেক ব্রাউজার তখন title-এর লেখাও বার্তার সাথে দেখায়, তাই সেখানে মানুষের ভাষায় নিয়মটা লিখুন। তবে title সব ফোনে বা screen reader-এ নিশ্চিত আসে না — জরুরি নির্দেশনা ঘরের পাশে সাধারণ লেখায়ও দিন।

:invalid, :valid আর :user-invalid — CSS-কে জানানো

ব্রাউজার যে প্রতিটি ঘরের validity জানে, CSS সেটা ধরতে পারে pseudo-class দিয়ে — ঘরের অবস্থা দেখে বাছাই করার selector. :valid আর :invalid সাথে সাথে অবস্থা দেখায়। সমস্যা: পাতা খোলার মুহূর্তেই ফাঁকা required ঘর :invalid — কিছু লেখার আগেই লাল দাগ, যেন বকা খাচ্ছেন। সমাধান :user-invalid আর :user-valid — এরা কাজ করে কেবল ব্যবহারকারী ঘরটি নিয়ে কিছু করার পর (লিখে অন্য ঘরে গেলে, বা জমা দিতে চাইলে)। ২০২৩ সাল থেকে সব প্রধান ব্রাউজারে আছে (Baseline 2023); পুরোনো ব্রাউজারে শুধু রংটা আসবে না, ফর্ম ঠিকই চলবে। সাজানোর পুরো কৌশল পর্ব ৪৩-এ; এখানে এক ঝলক:

<style>
  input:user-invalid { outline: 3px solid crimson; }
  input:user-valid   { outline: 3px solid seagreen; }
</style>
<form>
  <p><label>নাম* <input name="name" required minlength="3" maxlength="40"></label></p>
  <p><label>মোবাইল* <input type="tel" name="mobile" required
     pattern="01[3-9][0-9]{8}" title="১১ অঙ্ক, 01 দিয়ে শুরু — যেমন 01712345678"></label>
     <small>১১ অঙ্ক, যেমন 01712345678</small></p>
  <p><label>ইমেইল <input type="email" name="email"></label></p>
  <p><label>বয়স* <input type="number" name="age" required min="18" max="35"></label></p>
  <p><label>সপ্তাহে কত ঘণ্টা সময় দেবেন? <input type="number" name="hours"
     min="0" max="20" step="0.5" value="2"></label></p>
  <p><label>পোর্টফোলিও লিংক <input type="url" name="site"></label></p>
  <button>আবেদন জমা দিন</button>
</form>

শুরুতে কোনো লাল দাগ নেই — যদিও নাম, মোবাইল, বয়স ফাঁকা এবং আসলে invalid. এবার কিছু না লিখে “আবেদন জমা দিন” চাপুন: ব্রাউজার নামের ঘরে focus নিয়ে বার্তা দেখাবে, আর ভুল ঘরগুলো লাল হবে। মোবাইলে 0171234567 (১০ অঙ্ক) লিখে বার্তা দেখুন, তারপর একটি অঙ্ক যোগ করুন — সবুজ। বয়সে 17 বা 40 লিখুন; সময়ে 2.3 লিখুন (step-এর বার্তা); লিংকে abcltech.com লিখুন (scheme নেই বলে অবৈধ)। সব ঠিক হলে নিচে জমার তালিকা আসবে। চেষ্টা করুন: CSS-এ :user-invalid-কে :invalid করুন — পাতা খুলতেই ফাঁকা ঘরগুলো লাল হয়ে যাবে; এই অভিজ্ঞতাটাই এড়াতে চাই।

আরও গভীরে: WHATWG নিয়মে ব্রাউজার pattern-কে ^(?: আর )$ দিয়ে মুড়ে JavaScript-এর RegExp হিসেবে বানায়, আর আধুনিক ব্রাউজারে v flag দিয়ে — যার ফলে [\w-]-এর মতো কিছু পুরোনো লেখা এখন ভুল ধরা হয় (লিখতে হয় [\w\-]), আর ভুল regex পেলে ব্রাউজার চুপচাপ pattern-টাই উপেক্ষা করে। maxlength আর minlength অক্ষর গোনে UTF-16 একক হিসেবে, চোখে দেখা অক্ষর হিসেবে নয় — তাই বাংলায় “ক্ষ” (ক + ্ + ষ) গোনা হয় ৩, আর বাংলা নামের জন্য খুব কড়া maxlength দিলে মানুষ নিজের নামই পুরো লিখতে পারেন না।

৮ · novalidate, formnovalidate, disabled আর readonly

যাচাই বন্ধ করার দুই উপায়

  • <form novalidate> — পুরো ফর্মের built-in যাচাই বন্ধ। সাধারণত তখন, যখন JavaScript দিয়ে নিজের সুন্দর ভুল-বার্তা দেখাতে চান: ব্রাউজারের বুদবুদ বন্ধ, কিন্তু validity রিপোর্ট ঠিকই থাকে, আর JavaScript সেটা পড়ে নিজের মতো দেখায়।
  • <button formnovalidate> — শুধু ওই বোতামটি চাপলে যাচাই হবে না। ক্লাসিক উদাহরণ: “খসড়া রাখুন” বোতাম। অর্ধেক পূরণ করা আবেদনও সেভ করা যায়, কিন্তু “চূড়ান্ত জমা” বোতামে পুরো যাচাই হয়।

disabled বনাম readonly

দুটোই বলে “এই ঘর বদলানো যাবে না”, কিন্তু বাকি সব আচরণে আলাদা। পরীক্ষার খাতার কভার পাতা ভাবুন: রোল নম্বর আগে থেকে ছাপানো — আপনি বদলাতে পারবেন না, কিন্তু খাতার সাথে সেটা জমা যায় (readonly). আর কাটা দাগ দেওয়া একটি পুরোনো ঘর, যা এ বছর প্রযোজ্যই নয় — সেটা কেউ পড়েই না (disabled).

আচরণreadonlydisabled
মান বদলানো যায়?নানা
জমার সাথে মান যায়?হ্যাঁনা
Tab দিয়ে focus, লেখা কপি?হ্যাঁনা
validation হয়?না (বাদ পড়ে)না (বাদ পড়ে)
কোথায় খাটে?শুধু লেখার ঘর (text, date, number, textarea…); checkbox, radio, select-এ কাজ করে নাসব কন্ট্রোল আর বোতাম; পুরো <fieldset disabled>-ও
চেহারাসাধারণত সাধারণ ঘরের মতোধূসর, ফ্যাকাশে
<form>
  <p><label>রোল নম্বর <input name="roll" value="101" readonly></label></p>
  <p><label>পুরোনো আইডি <input name="oldid" value="A-7" disabled></label></p>
  <p><label>মোবাইল* <input name="mobile" required></label></p>
  <button>চূড়ান্ত জমা</button>
  <button formnovalidate>খসড়া রাখুন</button>
</form>

মোবাইল ফাঁকা রেখে “চূড়ান্ত জমা” চাপুন — বার্তা আসবে। এবার “খসড়া রাখুন” চাপুন — যাচাই ছাড়াই জমা হবে: roll=101&mobile=. খেয়াল করুন, oldid নেই — disabled ঘর পাঠানো হয় না, আর readonly রোল নম্বর ঠিকই গেছে। কি-বোর্ডে Tab চেপে ঘুরুন: রোল নম্বরের ঘরে focus আসে, পুরোনো আইডিতে আসে না। চেষ্টা করুন: <form>-কে <form novalidate> করুন — এবার “চূড়ান্ত জমা”-ও যাচাই ছাড়া জমা হবে। তারপর মোবাইলের ঘরে readonly যোগ করুন — required থাকলেও আর আপত্তি নেই, কারণ readonly ঘর যাচাই থেকেই বাদ।

“জমা দিলে আসলে কী যায়” — এটা ফর্মের সবচেয়ে কম বোঝা অংশ। ব্রাউজার জমার আগে একটি তালিকা বানায় — সার্ভারে যাওয়া নাম=মান জোড়ার তালিকা। পুরোনো spec একে বলত form data set, আজকের WHATWG নিয়মে নাম entry list. নিচের ফর্মে লাইন ধরে ধরে দেখুন কে ঢোকে আর কে বাদ পড়ে:

1<form>2  <input name="name" value="রহিম">3  <input type="checkbox" name="news">4  <input type="checkbox" name="terms" checked>5  <input type="radio" name="pay" value="bkash" checked>6  <input type="radio" name="pay" value="cod">7  <select name="tag" multiple> (html, css বাছা; js নয়)8  <input name="roll" value="101" readonly>9  <input name="oldid" value="A-7" disabled>10  <input type="hidden" name="price" value="500">11</form>
কে যাচ্ছে?
name
news
terms
pay
tag
roll
oldid
price
  1. সাধারণ লেখার ঘর. name আর value — জোড়াটি তালিকায় উঠল। মনে রাখবেন, name না থাকলে ঘরটি কখনোই পাঠানো হয় না, যত সুন্দর লেখাই থাকুক — পর্ব ০৮-এর সেই নিয়ম।
  2. দুটি checkbox. news-এ টিক নেই, তাই সে নামসহ পুরো বাদ। terms-এ টিক আছে কিন্তু value নেই, তাই পাঠানো হলো ডিফল্ট মান on. সার্ভার “news=না” পায় না — কিছুই পায় না।
  3. radio দল. একই name-এর দুটি radio-র মধ্যে যেটি checked, শুধু তার value যায়: pay=bkash. দলের কোনোটিই বাছা না থাকলে pay নামটাই অনুপস্থিত থাকত।
  4. multiple select. যতগুলো option বাছা, ততবার একই নাম: tag=html, tag=css. সার্ভারের কোড একে একটি তালিকা হিসেবে পড়ে। একাধিক checkbox-এ একই name দিলেও ঠিক এমন হয়।
  5. readonly বনাম disabled. readonly রোল নম্বর তালিকায় উঠল; disabled পুরোনো আইডি বাদ। তাই সার্ভারের দরকার এমন কিন্তু ব্যবহারকারীর বদলানোর নয় এমন মান readonly-তে রাখুন — disabled-এ রাখলে সার্ভার মানটি পাবেই না।
  6. hidden — এবং বড় সতর্কতা. price=500 চোখে না দেখা গেলেও তালিকায় উঠল। কিন্তু (!) চিহ্নটা খেয়াল করুন: যে কেউ DevTools খুলে value 500-কে 5 করে দিতে পারেন। দাম, ছাড়, ব্যবহারকারীর পরিচয় — এমন কিছু কখনো hidden ঘরের ওপর বিশ্বাস করে নেবেন না। (আসল request-এ বাংলা লেখা percent-encoding হয়ে যায়; এখানে সহজ রাখতে সরাসরি দেখানো হলো।)

৯ · নিজের নিয়ম, setCustomValidity — আর সার্ভারে আবার যাচাই

যখন attribute যথেষ্ট নয়

কিছু নিয়ম attribute দিয়ে লেখা যায় না: “দুই ঘরের পাসওয়ার্ড মিলতে হবে”, “কমপক্ষে একটি বিষয় বাছুন”, “শেষ তারিখ শুরুর তারিখের পরে হতে হবে”. তখন একটু JavaScript লাগে — কিন্তু পুরো যাচাই নতুন করে লেখার দরকার নেই। ব্রাউজারের যাচাই-ব্যবস্থাতেই নিজের নিয়ম যোগ করা যায় setCustomValidity() দিয়ে: এতে একটি বার্তা দিলে ঘরটি invalid হয়ে যায় (আর জমার সময় ঠিক সেই বার্তাটিই দেখায়); ফাঁকা লেখা '' দিলে আবার valid. সবচেয়ে প্রচলিত ভুল — ঠিক হয়ে গেলে '' দিতে ভুলে যাওয়া; তখন ঘরটি চিরকাল invalid থাকে আর ফর্ম আর কখনো জমা হয় না।

নিচের ছোট স্ক্রিপ্টে নিজেই দেখুন। ফর্মটি ওপরে দেখাবে, আর স্ক্রিপ্টের রিপোর্ট নিচে:

const pw1 = document.getElementById('pw1');
const pw2 = document.getElementById('pw2');
const mob = document.getElementById('mob');

// ১) ব্রাউজারের নিজের রিপোর্ট পড়া
console.log('mobile valid?', mob.validity.valid, '| patternMismatch:', mob.validity.patternMismatch);

// ২) নিজের নিয়ম: দুই পাসওয়ার্ড মিলতে হবে
function checkMatch() {
  pw2.setCustomValidity(pw1.value === pw2.value ? '' : 'দুটি পাসওয়ার্ড মেলেনি');
}
pw1.addEventListener('input', checkMatch);
pw2.addEventListener('input', checkMatch);
checkMatch();
console.log('pw2 customError:', pw2.validity.customError, '|', pw2.validationMessage);

// ৩) ব্যবহারকারী ঠিক করলেন
pw2.value = 'dhaka2026';
checkMatch();
console.log('after fix, pw2 valid?', pw2.validity.valid);
console.log('whole form valid?', document.getElementById('reg').checkValidity());

প্রথম লাইন: mobile valid? false | patternMismatch: true — নম্বরে ১০ অঙ্ক। দ্বিতীয়: pw2 customError: true | দুটি পাসওয়ার্ড মেলেনি — আমাদের নিয়ম আর আমাদের বাংলা বার্তা। তৃতীয়: ঠিক করার পর true, কারণ checkMatch এবার '' দিয়েছে। শেষ লাইন তবু false — মোবাইল নম্বর এখনো ভুল; checkValidity() পুরো ফর্মের সব ঘর একসাথে দেখে। চেষ্টা করুন: শেষ console.log-এর ঠিক আগে mob.value = '01712345678'; লাইনটি যোগ করুন — শেষ লাইন true হবে। আর প্রিভিউর দ্বিতীয় ঘরে নিজে টাইপ করুন — প্রতিটি অক্ষরে checkMatch আবার চলে।

এই পর্বে JavaScript এটুকুই। ফর্মের সাথে JavaScript-এর পুরো কাজ — ঘটনা ধরা, নিজের ভুল-বার্তা দেখানো, সার্ভারে পাঠানো — JavaScript কোর্সের ফর্ম ও validation পর্বে দেখবেন; regex নিয়ে আরও গভীরে যেতে আছে regex পর্ব।

সবচেয়ে জরুরি কথা — ব্রাউজারের যাচাই নিরাপত্তা নয়

এতক্ষণ যা দেখলেন, তার সবই ঘটে ব্যবহারকারীর নিজের কম্পিউটারে — তাই একে বলে client-side validation. আর ব্যবহারকারীর কম্পিউটার পুরোপুরি ব্যবহারকারীর নিয়ন্ত্রণে। ভেবে দেখুন, কেউ চাইলে কী কী করতে পারেন:

  • DevTools খুলে required বা pattern মুছে দিতে পারেন — দুই সেকেন্ডের কাজ।
  • hidden ঘরের price=500-কে price=5 করে দিতে পারেন।
  • ব্রাউজার একদমই ব্যবহার না করে সরাসরি সার্ভারে request পাঠাতে পারেন — তখন আপনার HTML-এর কোনো নিয়মই সেখানে নেই:
curl -X POST https://shop.example.com/order -d "product=42&price=5&mobile=hello"

কাউন্টারের লোকটির কথা আবার ভাবুন: কেউ পেছনের দরজা দিয়ে সরাসরি অফিসে ঢুকে ফর্ম জমা দিলে কাউন্টারের যাচাই কোনো কাজে আসে না। তাই অফিসের ভেতরে, অর্থাৎ সার্ভারে, প্রতিটি তথ্য আবার যাচাই করতে হয় — একে বলে server-side validation. দাম সার্ভার নেবে নিজের ডেটাবেস থেকে, ফর্ম থেকে নয়; মোবাইল নম্বর সার্ভার আবার মেলাবে; ফাইলের ধরন সার্ভার নিজে পরীক্ষা করবে, accept-এর ভরসায় নয়।

মূল ধারণা

ক্লায়েন্টের যাচাই সৎ ব্যবহারকারীর সুবিধার জন্য — দ্রুত ভুল ধরা, বারবার পাতা লোড না হওয়া, সার্ভারে কম অপ্রয়োজনীয় request. সার্ভারের যাচাই সবার কাছ থেকে সিস্টেমকে রক্ষার জন্য। প্রথমটা থাকা ভালো; দ্বিতীয়টা না থাকলে সাইট অরক্ষিত। নিরাপত্তার জগতের পুরোনো নীতি: “ব্যবহারকারীর পাঠানো কোনো তথ্যে বিশ্বাস করবেন না।”

অ্যাক্সেসিবিলিটির দিক: WCAG 2.2-এর ৩.৩.১ (Error Identification) বলে ভুল হলে কোন ঘরে ভুল তা লেখায় জানাতে হবে, আর ৩.৩.৩ (Error Suggestion) বলে সম্ভব হলে কীভাবে ঠিক করবেন তাও বলতে হবে — “ভুল ইনপুট” নয়, “১১ অঙ্কের নম্বর লিখুন, যেমন 01712345678”. নিজের বার্তা ঘরের সাথে জুড়ে দেওয়ার কৌশল পর্ব ১২ আর ৪৩-এ।

১০ · AI-এর যুগে — AI-এর বানানো ফর্ম যাচাই

“একটা রেজিস্ট্রেশন ফর্ম বানিয়ে দাও” — AI মুহূর্তে সুন্দর কোড দেবে। কিন্তু ফর্মে ছোট গলদ বড় ক্ষতি করে: কেউ পূরণই করতে পারেন না, ভুল তথ্য ঢোকে, বা নিরাপত্তার ফাঁক থাকে। পুরোনো কোড থেকে শেখা AI কিছু ভুল বারবার করে:

AI-এর ভুলকেন সমস্যাঠিক উপায়
div আর ছবি দিয়ে নকল checkbox বা radioকি-বোর্ডে চলে না, screen reader চেনে না, জমাও হয় নাআসল <input type="checkbox">, চেহারা CSS-এ
label-এর বদলে শুধু placeholderলিখতে শুরু করলেই প্রশ্নটা হারিয়ে যায়; accessible name দুর্বলপ্রতিটি ঘরে <label>
radio দলে fieldset/legend নেই, বা দলের name আলাদাপ্রশ্ন শোনা যায় না, বা একসাথে কয়েকটি বাছা যায়একই name, <fieldset> + <legend>
ফোন নম্বর বা NID-তে type="number"শুরুর 0 হারায়, pattern আর maxlength কাজ করে নাtype="tel" বা text + inputmode="numeric"
শুধু JavaScript দিয়ে যাচাই, সার্ভারের কথা নেইনিরাপত্তার ফাঁকHTML attribute + সার্ভারে আবার যাচাই
নামে pattern="[A-Za-z ]+"বাংলা নাম লেখাই যায় না!নামে pattern না দেওয়া, বা খুব উদার নিয়ম
দরকারি মান disabled-এ রেখে জমার আশাdisabled ঘর জমা হয় নাreadonly, বা সার্ভারেই মানটি রাখা

AI-কে শর্তসহ কাজ দিন, আর শেষে তাকে দিয়েই নিজের কাজ ব্যাখ্যা করিয়ে নিন — ব্যাখ্যা করতে গিয়ে প্রায়ই ভুল বেরিয়ে আসে:

তুমি একজন অ্যাক্সেসিবিলিটি-সচেতন ফ্রন্ট-এন্ড ডেভেলপার। একটি কোচিং সেন্টারের ভর্তি ফর্ম বানাও, শুধু HTML (CSS ন্যূনতম)। ঘর: নাম, বাংলাদেশি মোবাইল নম্বর, ইমেইল (ঐচ্ছিক), জন্মতারিখ, জেলা (select, বিভাগ অনুযায়ী optgroup), আগ্রহের কোর্স (checkbox দল), ক্লাসের শিফট (radio দল), মতামত (textarea), শর্তাবলি মানছি (checkbox). শর্ত: ১. প্রতিটি ঘরে label; checkbox আর radio দল fieldset ও legend-এ। ২. মোবাইলে type="tel", pattern="01[3-9][0-9]{8}", title, আর ঘরের পাশে দৃশ্যমান উদাহরণ। ৩. নামে কোনো pattern দেবে না — বাংলা নাম লেখা যেতে হবে। ৪. type="number" শুধু আসল পরিমাণে; div দিয়ে কোনো কন্ট্রোল বানাবে না। ৫. কোনো hidden ঘরে দাম বা পরিচয় রাখবে না। শেষে একটি তালিকা দাও: প্রতিটি ঘরের কোন কোন validation attribute দিয়েছ এবং কেন, আর সার্ভারে আবার কী কী যাচাই করতে হবে।

AI-এর দেওয়া ফর্ম হাতে পেলে — যাচাইয়ের চেকলিস্ট

পরীক্ষা ও ইন্টারভিউতে — বিশ্ববিদ্যালয়, চাকরি বা ফ্রন্ট-এন্ড ইন্টারভিউর পরীক্ষায় এ ধরনের প্রশ্ন প্রায়ই আসে:

  • checkbox আর radio-র পার্থক্য? radio দল কীভাবে তৈরি হয়? — checkbox-এ যত খুশি, radio-তে একটিমাত্র; একই name দিলে radio-গুলো এক দল হয়।
  • disabled আর readonly-এর পার্থক্য? — দুটোই বদলাতে দেয় না; readonly-র মান জমা হয় ও focus পায়, disabled-এর হয় না।
  • select আর datalist-এর পার্থক্য? — select-এ শুধু তালিকার মান বাছা যায়; datalist শুধু পরামর্শ, মুক্ত লেখাও চলে।
  • progress আর meter কখন কোনটি? — কাজ কতদূর এগোল তা progress; জানা সীমার মধ্যে একটি মাপ (চার্জ, স্টোরেজ) meter.
  • HTML validation থাকলে সার্ভারে যাচাই কেন? — ক্লায়েন্টের যাচাই যে কেউ এড়াতে পারে (DevTools, সরাসরি request); নিরাপত্তা আর সঠিক তথ্যের দায়িত্ব সার্ভারের।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন। এগুলো ফর্মকে শুধু ট্যাগের সমষ্টি নয়, মানুষ আর সিস্টেমের মধ্যে একটি চুক্তি হিসেবে দেখতে শেখাবে।

প্র ০১মোবাইল নম্বর, NID বা রোল নম্বর তো সংখ্যাই — তাহলে এগুলোর জন্য type="number" কেন ভুল?

কারণ এগুলো দেখতে সংখ্যা হলেও আসলে পরিচয়-চিহ্ন, পরিমাণ নয়। একটি সহজ পরীক্ষা: এই মানগুলোর ওপর কি কখনো যোগ-বিয়োগ করবেন? দুটি মোবাইল নম্বর যোগ করার কোনো মানে নেই। type="number" বানানো হয়েছে পরিমাণের জন্য — বয়স, কতটি পণ্য, কত টাকা — আর সেই উদ্দেশ্যের সাথে মিলিয়ে তার আচরণ ঠিক করা।

সমস্যাগুলো একে একে দেখুন। এক, শুরুর শূন্য: 01712345678 সংখ্যা হিসেবে 1712345678-এর সমান, আর সার্ভারের কোড মানটিকে সংখ্যায় রূপান্তর করলে শুরুর 0 হারিয়ে যায়। দুই, অনেক ব্রাউজারে number ঘরে ওপর-নিচ তীরের বোতাম থাকে, আর ঘরে মাউস রেখে চাকা ঘোরালে বা তীর চাপলে মান বদলে যেতে পারে — কারও মোবাইল নম্বর এক বেড়ে গেলে কী বিপদ! তিন, number ঘর e অক্ষর গ্রহণ করে, কারণ 1e5 একটি বৈধ সংখ্যা। চার, pattern, minlength আর maxlength number-এ খাটেই না — তাই “ঠিক ১১ অঙ্ক” বলার উপায় থাকে না। পাঁচ, ১৭ অঙ্কের মতো বড় পরিচয় নম্বর JavaScript-এর সাধারণ সংখ্যায় পুরোপুরি নির্ভুল রাখা যায় না — খুব বড় সংখ্যায় শেষের অঙ্ক গোল হয়ে যেতে পারে।

ঠিক উপায়: ফোনের জন্য type="tel" — ফোনে সংখ্যার কি-বোর্ড আসে, কিন্তু মানটি লেখা হিসেবেই থাকে, আর pattern দিয়ে আকার মেলানো যায়। NID, রোল বা কার্ড নম্বরের জন্য type="text" সাথে inputmode="numeric" আর একটি pattern. এতে কি-বোর্ড সংখ্যার, কিন্তু আচরণ লেখার।

এই প্রশ্নটা আসলে একটা বড় শিক্ষার ছোট রূপ: ডেটার চেহারা নয়, তার অর্থ আর ব্যবহার দেখে ধরন বাছাই করুন। ডেটাবেসেও একই নিয়ম — ফোন নম্বর সংখ্যার কলামে রাখলে একই বিপদ।

মূল উপলব্ধি: যে মানের ওপর হিসাব করবেন না, তা সংখ্যা নয় — লেখা। ঠিক type বাছাই মানে ব্রাউজারের আচরণকে আপনার ডেটার অর্থের সাথে মেলানো।

প্র ০২ব্রাউজারে built-in validation থাকতে এত সাইট এখনো নিজের JavaScript দিয়ে যাচাই করে কেন? তাহলে কি HTML-এর যাচাই অর্থহীন?

ইতিহাসটা বুঝলে উত্তর পরিষ্কার হয়। Web Forms 2.0-এর ধারণা থেকে required, pattern আর নতুন type এসেছিল HTML5-এ, কিন্তু প্রথম কয়েক বছর ব্রাউজারগুলোর বাস্তবায়ন ছিল অসম। কোনো ব্রাউজার বার্তার বুদবুদ দেখাত, কোনোটা চুপচাপ জমা আটকে দিত, কোনোটা কিছুই করত না। বুদবুদের চেহারা CSS দিয়ে বদলানো যেত না, বার্তা আসত ব্রাউজারের ভাষায় — বাংলা সাইটে ইংরেজি বার্তা, বা উল্টো। আর :invalid পাতা খোলার মুহূর্তেই ফাঁকা ঘরকে লাল করত। ডিজাইনাররা তাই বুদবুদ বন্ধ করে (novalidate) নিজের সুন্দর বার্তা বানাতেন।

পরিস্থিতি এখন অনেক বদলেছে। :user-invalid আর :user-valid ২০২৩ সালে সব প্রধান ব্রাউজারে এসে “আগেভাগে লাল” সমস্যাটি মিটিয়েছে। আর সবচেয়ে বড় কথা, আধুনিক পদ্ধতিতে HTML-এর যাচাই ফেলে দেওয়া হয় না — বরং এর ওপরেই দাঁড়ানো হয়। attribute দিয়ে নিয়ম লেখা থাকে, ব্রাউজার validity রিপোর্ট বানায় (valueMissing, patternMismatch…), আর JavaScript শুধু সেই রিপোর্ট পড়ে নিজের ভাষায় ও নিজের নকশায় বার্তা দেখায়। একে বলে Constraint Validation API.

এই পদ্ধতির সৌন্দর্য হলো progressive enhancement: JavaScript লোড না হলে (ধীর নেটওয়ার্ক, স্ক্রিপ্টে ভুল, পুরোনো ফোন) ব্রাউজারের নিজের যাচাই তো আছেই; JavaScript চললে অভিজ্ঞতা আরও ভালো। শুধু JavaScript-নির্ভর যাচাইয়ে স্ক্রিপ্ট ভাঙলে যাচাই-ই থাকে না। তাই novalidate HTML-এ সরাসরি না লিখে JavaScript দিয়ে বসানোর পরামর্শ দেওয়া হয় — স্ক্রিপ্ট চললে তবেই বুদবুদ বন্ধ।

তবু কিছু নিয়ম HTML পারে না: দুই ঘরের তুলনা, “কমপক্ষে একটি”, সার্ভার থেকে জেনে বলা “এই ইউজারনেম আগেই নেওয়া” — এগুলোর জন্য setCustomValidity বা নিজের কোড লাগবেই।

মূল উপলব্ধি: HTML-এর যাচাই ভিত্তি, JavaScript তার ওপরের তলা। ভিত্তি ফেলে দিয়ে তলা বানালে, স্ক্রিপ্ট না চললে পুরো দালানই ধসে পড়ে।

প্র ০৩ক্লায়েন্টে এত যাচাই করেও সার্ভারে আবার একই কাজ কেন? এটা কি সময় আর কোডের অপচয় নয়?

দুই জায়গার যাচাই আসলে একই কাজ নয় — তাদের উদ্দেশ্য আলাদা। নিরাপত্তার জগতে একটা ধারণা আছে, “trust boundary” বা বিশ্বাসের সীমানা। আপনার সার্ভার, তার কোড, তার ডেটাবেস — এগুলো আপনার নিয়ন্ত্রণে, সীমানার ভেতরে। ব্যবহারকারীর ব্রাউজার সীমানার বাইরে; সেখানে কী চলছে, আপনি জানেন না, ঠিকও করতে পারেন না। সীমানা পেরিয়ে যা আসে, তার সবই সন্দেহজনক।

কল্পনা করুন একটি অনলাইন দোকান, যেখানে অর্ডার ফর্মে hidden ঘরে দাম রাখা, আর ব্রাউজারে min="1" max="5" দিয়ে পরিমাণ সীমিত। একজন অসৎ ব্যবহারকারী DevTools-এ দাম ৫ টাকা আর পরিমাণ ৫০০ করে দিলেন। সার্ভার যদি ফর্মের মানে বিশ্বাস করে, দোকান লোকসানে পড়বে। ফর্মের ঘর দিয়ে ডেটাবেস-কমান্ড ঢুকিয়ে দেওয়া (SQL injection) বা অন্য ব্যবহারকারীর পাতায় ক্ষতিকর স্ক্রিপ্ট বসানো (XSS) — ওয়েবের সবচেয়ে পরিচিত আক্রমণগুলোর অনেকগুলোর শুরু এই অবিশ্বাস্য ইনপুট থেকে। OWASP-এর মতো নিরাপত্তা সংস্থা বহু বছর ধরে এই আক্রমণগুলোকে সবচেয়ে বড় ঝুঁকির তালিকায় রাখছে।

তাহলে ক্লায়েন্টের যাচাই কেন? কারণ বেশিরভাগ ব্যবহারকারী সৎ, আর তাঁরা ভুল করেন অসাবধানে। তাঁদের জন্য সাথে সাথে বার্তা পাওয়া অনেক আরামদায়ক — বিশেষ করে ধীর মোবাইল নেটওয়ার্কে, যেখানে প্রতিবার সার্ভার ঘুরে আসতে কয়েক সেকেন্ড লাগে। সার্ভারেও কম অপ্রয়োজনীয় request যায়। অর্থাৎ ক্লায়েন্টের যাচাই হলো অভিজ্ঞতা, সার্ভারের যাচাই হলো নিরাপত্তা ও সত্যতা।

আর সার্ভার এমন অনেক কিছু যাচাই করে, যা ক্লায়েন্ট পারেই না: ইমেইলটি আগে নিবন্ধিত কি না, পণ্য স্টকে আছে কি না, এই ব্যবহারকারী এই কাজের অনুমতি পান কি না। অনেক দলে নিয়ম দুই জায়গায় একই রাখতে একই নিয়ম-তালিকা থেকে দুই দিকের কোড তৈরি করা হয় — তাতে “অপচয়”-ও কমে।

মূল উপলব্ধি: ক্লায়েন্টের যাচাই সৎ মানুষের জন্য সৌজন্য, সার্ভারের যাচাই সবার বিরুদ্ধে পাহারা। একটি অন্যটির বিকল্প নয় — দুটোই দরকার, আর দ্বিতীয়টি ছাড়া চলবেই না।

প্র ০৪ইমেইল বা নাম যাচাইয়ে কতটা কড়া হওয়া উচিত? “নিখুঁত” ইমেইল regex কেন কেউ ব্যবহার করে না?

ইমেইল ঠিকানার আনুষ্ঠানিক নিয়ম (RFC 5322 নামের মানদণ্ড) এত জটিল যে তা পুরোপুরি মেনে চলা regex কয়েকশো অক্ষরের হয়ে যায় — উদ্ধৃতি চিহ্নের ভেতরে space, মন্তব্য, অদ্ভুত চিহ্ন, সবই সেখানে বৈধ। মজার ব্যাপার, WHATWG-এর HTML spec নিজেই খোলাখুলি লিখেছে যে type="email"-এর সংজ্ঞাটি ইচ্ছা করে RFC 5322 থেকে সরে এসেছে (“willful violation”) — কারণ বাস্তবে কেউ ওই অদ্ভুত রূপগুলো ব্যবহার করেন না, আর কড়া নিয়ম বাস্তব মানুষকে আটকায়।

আসল সত্যটা হলো: regex যত নিখুঁতই হোক, তা কেবল বলতে পারে লেখাটি দেখতে ইমেইলের মতো কি না। rahim@gmial.com (বানান ভুল) দেখতে নিখুঁত, কিন্তু সেখানে চিঠি যাবে না। ঠিকানা সত্যি আছে আর ব্যবহারকারীরই — এটা জানার একমাত্র উপায় একটি যাচাই-ইমেইল বা OTP পাঠানো। তাই অভিজ্ঞ দলের নীতি: ব্রাউজারে সহজ আকার-যাচাই, তারপর যাচাই-লিংক।

নামের ক্ষেত্রে বিপদ আরও বড়। AI বা পুরোনো টিউটোরিয়াল প্রায়ই নামে [A-Za-z ]+ দেয় — তাতে “মোহাম্মদ রফিকুল ইসলাম” লেখাই যায় না, “O'Brien”-ও না, এমনকি এক শব্দের নামও কিছু নিয়মে আটকায়। বাংলাদেশে অনেকের নামের প্রথম অংশ নেই, কারও কারও খুব লম্বা নাম, কেউ বাংলায় লেখেন, কেউ ইংরেজিতে। মানুষের নাম সম্পর্কে যেকোনো “নিয়ম” প্রায় নিশ্চিতভাবে কোনো না কোনো আসল মানুষকে বাদ দেয়। তার ওপর maxlength বাংলা যুক্তাক্ষরে বাড়তি একক গোনে — খুব ছোট সীমা বাংলা নামকে আরও আগে কেটে দেয়।

আরেকটি প্রযুক্তিগত সীমা: আজকের type="email" ঠিকানার “@”-এর আগের অংশে বাংলার মতো অ-ইংরেজি অক্ষর গ্রহণ করে না, যদিও আন্তর্জাতিক ইমেইলের মানদণ্ডে তা সম্ভব। এমন ব্যবহারকারী কম, তবু জেনে রাখা ভালো যে ব্রাউজারের নিয়মও একটি আপস।

মূল উপলব্ধি: যাচাইয়ের লক্ষ্য অসাবধান ভুল ধরা, মানুষকে ছাঁচে ফেলা নয়। যত কড়া নিয়ম, তত বেশি আসল মানুষ আটকায় — আর সত্যতা যাচাইয়ের কাজ regex-এর নয়, যাচাই-বার্তার।

প্র ০৫disabled বোতাম আর disabled ঘর — অ্যাক্সেসিবিলিটির দিক থেকে কী সমস্যা তৈরি করে, আর বিকল্প কী?

disabled-এর মূল বৈশিষ্ট্য — focus পায় না — প্রথমে সুবিধা মনে হয়: অপ্রাসঙ্গিক ঘর এড়িয়ে Tab সামনে চলে যায়। কিন্তু একজন screen reader ব্যবহারকারী সাধারণত Tab বা ফর্মের ঘর ধরে ধরে চলেন। disabled ঘর তাঁর পথে না এলে তিনি হয়তো জানেনই না যে ঘরটি আছে, কেন বন্ধ, বা কী করলে খুলবে। চোখে দেখা মানুষ অন্তত একটি ফ্যাকাশে ঘর দেখেন।

সবচেয়ে প্রচলিত সমস্যা “disabled submit বোতাম” — সব ঘর ঠিক না হওয়া পর্যন্ত “জমা দিন” বন্ধ। ব্যবহারকারী বোতাম চাপতে পারেন না, কোনো বার্তাও পান না — কোন ঘরে ভুল তা খুঁজে বের করার দায় তাঁর ঘাড়ে। এর চেয়ে ভালো হলো বোতাম চালু রাখা, আর চাপলে ব্রাউজার বা আপনার কোড প্রথম ভুল ঘরে নিয়ে গিয়ে কারণ বলবে — built-in validation ঠিক এটাই করে।

আরেকটি দিক রং। WCAG-এর লেখার কনট্রাস্টের নিয়ম (১.৪.৩) নিষ্ক্রিয় কন্ট্রোলকে ছাড় দেয়, তাই disabled ঘর প্রায়ই খুব হালকা ধূসরে আঁকা হয় — কম দৃষ্টিশক্তির মানুষ, বা রোদে ফোন দেখা কেউ লেখাটি পড়তেই পারেন না। যদি সেখানে দরকারি তথ্য থাকে (যেমন আপনার রোল নম্বর), তাহলে disabled ভুল পছন্দ — readonly ঘর বা সাধারণ লেখায় দেখানো ভালো।

বিকল্প কী? (ক) দরকারি কিন্তু বদলানোর নয় এমন তথ্য — readonly বা সাধারণ লেখা। (খ) বোতাম চালু রেখে চাপার পর ব্যাখ্যা। (গ) একেবারেই অপ্রাসঙ্গিক অংশ — disabled না করে লুকিয়ে ফেলা, আর প্রাসঙ্গিক হলে দেখানো। (ঘ) উন্নত ক্ষেত্রে aria-disabled="true", যা বোতামকে “নিষ্ক্রিয়” ঘোষণা করে কিন্তু focus পেতে দেয় — তবে তখন ক্লিক আটকানোর কাজ নিজের JavaScript-এ করতে হয়, কারণ ARIA আচরণ বদলায় না, শুধু ঘোষণা করে।

মূল উপলব্ধি: “বন্ধ” করে দেওয়া সহজ, কিন্তু ব্যবহারকারীকে অন্ধকারে রাখে। ভালো ফর্ম আটকায় কম, ব্যাখ্যা করে বেশি।

অনুশীলন

প্রথম তিনটিতে কোড লিখতে হবে না — ভাবা আর অনুমান করাই আসল কাজ। চতুর্থটিতে একটি ছোট ফর্ম লিখবেন।

  1. কোন প্রশ্নে কোন কন্ট্রোল? একটি অনলাইন দোকানের চেকআউট ফর্ম: (ক) পেমেন্টের উপায় — বিকাশ, নগদ, কার্ড, ক্যাশ অন ডেলিভারি (খ) ডেলিভারির তারিখ (গ) ডেলিভারির এলাকা — ৬৪ জেলা (ঘ) “উপহার মোড়ক চাই” (ঙ) ডেলিভারিম্যানের জন্য নির্দেশনা (চ) সেবায় কতটা সন্তুষ্ট, ১ থেকে ৫.

    (ক) radio দল, একই name, fieldset + legend — চারটি বিকল্প, একটিই বাছা, সব চোখের সামনে থাকা ভালো। (খ) type="date", min-এ আগামীকাল (সার্ভার থেকে বসানো)। (গ) <select>, বিভাগ অনুযায়ী optgroup, প্রথম option ফাঁকা মানের + required. (ঘ) একটি checkbox. (ঙ) <textarea>, হয়তো maxlength দিয়ে. (চ) পাঁচটি radio (সবচেয়ে স্পষ্ট ও অ্যাক্সেসিবল), অথবা type="range" min="1" max="5" সাথে output — তবে range-এ মান চোখে পড়ে না বলে radio প্রায়ই ভালো।

  2. কী জমা হবে — অনুমান করুন: একটি ফর্মে আছে — <input name="city" value="খুলনা" disabled>, <input type="checkbox" name="agree" value="yes"> (টিক নেই), <input type="radio" name="size" value="m" checked>, <input type="radio" name="size" value="l">, <input value="১২৩"> (name নেই), <input type="hidden" name="ref" value="sms">. জমা দিলে কোন কোন নাম=মান যাবে?

    শুধু size=m&ref=sms. city — disabled, তাই বাদ। agree — টিক নেই, তাই বাদ (value থাকলেও)। size — দলের checked-টি, m. নাম ছাড়া ঘরটি — name নেই বলে কখনোই যায় না। ref — hidden হলেও যায়। ওপরের যেকোনো লাইভ এডিটরে ফর্মটি বসিয়ে মিলিয়ে নিন।

  3. pattern লিখুন ও পড়ুন: (ক) বাংলাদেশের পোস্ট কোড ৪ অঙ্কের — pattern কী হবে? (খ) জাতীয় পরিচয়পত্রের নম্বর সাধারণত ১০, ১৩ বা ১৭ অঙ্কের হয় — একটি pattern লিখুন। (গ) pattern="[0-9]{3,5}" কি 12, 1234, 123456 গ্রহণ করবে?

    (ক) [0-9]{4} — ব্রাউজার নিজেই শুরু-শেষ মুড়ে নেয়, তাই ঠিক ৪ অঙ্ক। (খ) [0-9]{10}|[0-9]{13}|[0-9]{17} — | মানে “অথবা”. চিন্তা নেই, ব্রাউজার পুরোটাকে ^(?:…)$ দিয়ে মোড়ায়, তাই তিনটি বিকল্পের প্রতিটিই পুরো লেখার সাথে মেলাতে হয়। (সংক্ষেপে [0-9]{10}([0-9]{3}([0-9]{4})?)?-ও লেখা যায়, তবে প্রথমটি পড়তে সহজ।) (গ) {3,5} মানে ৩ থেকে ৫টি অঙ্ক: 12 — না (২টি), 1234 — হ্যাঁ, 123456 — না (৬টি; অংশ মিললেও পুরোটা মেলে না)।

  4. নিজে লিখুন — বৃত্তির আবেদন ফর্ম: ঘর থাকবে: পূর্ণ নাম (বাধ্যতামূলক, কমপক্ষে ৩ অক্ষর), মোবাইল (বাধ্যতামূলক, বাংলাদেশি নম্বর), সর্বশেষ পরীক্ষার GPA (০ থেকে ৫, দুই দশমিক পর্যন্ত), পরিবারের মাসিক আয়ের সীমা (select), নথি (PDF, একাধিক), আর “তথ্য সত্য” checkbox (বাধ্যতামূলক)। সাথে একটি “খসড়া রাখুন” বোতাম, যা যাচাই ছাড়া জমা দেয়। ওপরের যেকোনো লাইভ এডিটরে লিখে পরীক্ষা করুন।

    একটি সম্ভাব্য উত্তর:

    <form method="post" enctype="multipart/form-data">
      <p><label for="fn">পূর্ণ নাম*</label>
         <input id="fn" name="fullname" required minlength="3"></p>
      <p><label for="mb">মোবাইল*</label>
         <input id="mb" name="mobile" type="tel" required pattern="01[3-9][0-9]{8}"
                title="১১ অঙ্ক, যেমন 01712345678"> <small>যেমন 01712345678</small></p>
      <p><label for="gpa">GPA</label>
         <input id="gpa" name="gpa" type="number" min="0" max="5" step="0.01"></p>
      <p><label for="inc">পরিবারের মাসিক আয়*</label>
         <select id="inc" name="income" required>
           <option value="">— বেছে নিন —</option>
           <option value="lt15">১৫,০০০ টাকার কম</option>
           <option value="15-30">১৫,০০০–৩০,০০০ টাকা</option>
           <option value="gt30">৩০,০০০ টাকার বেশি</option>
         </select></p>
      <p><label for="doc">নথি (PDF)</label>
         <input id="doc" name="docs" type="file" accept=".pdf,application/pdf" multiple></p>
      <p><label><input type="checkbox" name="truth" value="yes" required>
         আমি নিশ্চিত করছি, সব তথ্য সত্য</label></p>
      <button>আবেদন জমা দিন</button>
      <button formnovalidate>খসড়া রাখুন</button>
    </form>

    খেয়াল করুন: GPA পরিমাণ, তাই number চলে, আর step="0.01" না দিলে 4.25 অবৈধ হতো। মোবাইল tel. নামে pattern নেই, যাতে বাংলা নাম লেখা যায়। ফাইলের জন্য method="post" আর enctype. আর সার্ভারে আবার সব যাচাই — বিশেষ করে ফাইলটি আসলেই PDF কি না।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএকটি HTML ফর্ম জমা দেওয়া থেকে তথ্য সংরক্ষণ পর্যন্ত ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. ব্যবহারকারী submit বোতাম চাপেন
  2. ব্রাউজার দেখে novalidate বা formnovalidate আছে কি না
  3. প্রতিটি ঘরের শর্ত (required, pattern…) মেলানো হয়
  4. সব ঠিক থাকলে নাম=মান জোড়ার তালিকা বানিয়ে request পাঠানো হয়
  5. সার্ভার প্রতিটি মান আবার যাচাই করে, তারপর সংরক্ষণ করে

একটি HTML ফর্মে কয়েকটি radio বোতাম এমনভাবে কাজ করে যে একটি বাছলে আগেরটি নিজে থেকে উঠে যায়। এর কারণ কী?

  • সবগুলোর id একই
  • সবগুলো একটি fieldset-এর ভেতরে আছে
  • সবগুলোর name একই
  • সবগুলোর value একই

একটি ফর্মে <input type="checkbox" name="sms" value="yes"> আছে, আর ব্যবহারকারী টিক না দিয়েই ফর্ম জমা দিলেন। সার্ভারে sms সম্পর্কে কী পৌঁছাবে?

  • sms=no
  • কিছুই না — sms নামটাই থাকবে না
  • sms=yes
  • sms=on

<input pattern="01[3-9][0-9]{8}"> ঘরে নিচের কোন মানটি বৈধ?

  • 0181234567
  • 01212345678
  • +8801812345678
  • 01812345678

HTML ফর্মের ঘরে readonly আর disabled সম্পর্কে কোন কথাটি সঠিক?

  • readonly ঘরের মান জমার সাথে যায়, disabled ঘরের মান যায় না
  • disabled ঘরের মান জমার সাথে যায়, readonly ঘরের মান যায় না
  • দুটি একই — শুধু চেহারায় পার্থক্য
  • readonly সব ধরনের কন্ট্রোলে কাজ করে, disabled শুধু লেখার ঘরে

একটি ফর্মে required, pattern আর min-max দিয়ে পুরো যাচাই করা আছে। তবু সার্ভারে আবার যাচাই করতে হয় কেন?

  • কারণ বেশিরভাগ ব্রাউজার এই attribute চেনে না
  • যাতে ফর্ম দ্রুত লোড হয়
  • কারণ ব্যবহারকারী ব্রাউজারের যাচাই সহজেই এড়িয়ে সরাসরি তথ্য পাঠাতে পারেন
  • কারণ HTML attribute-গুলো সার্ভারে গিয়ে আবার চালু হয়

একটি অ্যাপের সেটিংস পাতায় ফোনের ব্যাটারিতে কত চার্জ আছে (০–১০০%) দেখাতে কোন HTML element সবচেয়ে উপযুক্ত?

  • <progress>
  • <meter>
  • <input type="range">
  • <output>

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. যত খুশি — checkbox; একটিমাত্র — radio, দল তৈরি হয় একই name দিয়ে, প্রশ্ন থাকে <fieldset>-এর <legend>-এ। টিক না দেওয়া checkbox কিছুই পাঠায় না।
  2. লম্বা তালিকা — select (optgroup, multiple); বড় লেখা — textarea; শুধু পরামর্শ — datalist. মাপ — meter, অগ্রগতি — progress, ফল — output.
  3. ঠিক type (date, range, color, file, email, tel, url) মানে বিনামূল্যে UI, কি-বোর্ড আর যাচাই; ফোন নম্বর number নয়, tel.
  4. required, min/max/step, minlength/maxlength, pattern — pattern পুরো লেখার সাথে মেলে; title আর দৃশ্যমান উদাহরণে নিয়ম বলুন; :user-invalid ব্যবহারকারী কিছু করার পরই লাল করে।
  5. readonly জমা হয়, disabled হয় না; formnovalidate খসড়ার জন্য — আর ব্রাউজারের যাচাই সুবিধা, নিরাপত্তা নয়: সার্ভারে আবার যাচাই করতেই হবে।

পরের পর্বে: ছোট ছোট অংশ — লেখা, ছবি, তালিকা, ফর্ম — সবই শিখলেন। এবার পুরো পাতার কাঠামো: header, nav, main, article, section আর footer দিয়ে এমন পাতা, যার প্রতিটি অংশের ভূমিকা ব্রাউজার, screen reader আর সার্চ ইঞ্জিন বুঝতে পারে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান