2 điểm bởi GN⁺ 2024-10-29 | 1 bình luận | Chia sẻ qua WhatsApp
  • Biểu mẫu HTML vốn đã có các tính năng xác thực native như required, type="email", pattern, maxlength, setCustomValidity, nhưng trên thực tế mức độ sử dụng vẫn thấp so với phạm vi tính năng
  • setCustomValidity, công cụ mạnh nhất, có thể xử lý logic xác thực tùy ý và các trường hợp phức tạp, nhưng vì chỉ được cung cấp dưới dạng phương thức DOM nên không thật sự phù hợp với các component khai báo
  • Trong môi trường như React, để xác thực giá trị ban đầu cho đúng, useRef, useLayoutEffect, onChange dễ bị đan xen với nhau, và cùng một logic xác thực dễ bị lặp lại ở lần render ban đầu và trong handler thay đổi
  • Nếu có một abstraction dạng thuộc tính như custom-validity, các phép xác thực có phụ thuộc giữa trạng thái và input, chẳng hạn kiểm tra bất đồng bộ tên người dùng có bị trùng hay không hoặc xác nhận mật khẩu, có thể được biểu diễn tại một nơi
  • Mức độ áp dụng thấp của xác thực biểu mẫu native gần với vấn đề tính dễ dùng của API hơn là thiếu tính năng; nếu một API khai báo được đưa vào đặc tả HTML, khả năng tận dụng sẽ lớn hơn

Những gì xác thực biểu mẫu HTML đã cung cấp

  • Cách đơn giản nhất để chặn input rỗng là thêm thuộc tính required
  • Có thể đặt ràng buộc cho input theo ba cách chính
    • Dùng kiểu input như type="email", type="number", type="url"
    • Dùng thuộc tính ràng buộc như pattern, maxlength
    • Dùng phương thức DOM setCustomValidity của input
  • setCustomValidity là phương tiện mạnh nhất vì có thể xử lý logic xác thực tùy ý và các trường hợp phức tạp
  • Hai cách đầu có thể được khai báo bằng thuộc tính HTML, nhưng setCustomValidity khác ở chỗ cần gọi phương thức
  • Tài liệu tham khảo về khác biệt giữa thuộc tính DOM và property được liên kết tại Attributes vs Properties

Điểm khiến setCustomValidity trở nên bất tiện

  • setCustomValidity không có thuộc tính HTML tương ứng, mà chỉ được lộ ra dưới dạng phương thức
  • Khi truyền vào một chuỗi, input chuyển sang trạng thái invalid, và trình duyệt hiển thị chuỗi đó làm lý do xác thực thất bại
  • Khi truyền vào chuỗi rỗng, input sẽ ở trạng thái valid miễn là không có ràng buộc nào khác
  • Để tự triển khai hành vi như required, cần gọi setCustomValidity mỗi khi giá trị thay đổi
  • Tuy nhiên, ban đầu input ở trạng thái valid, nên nếu nhấn nút submit ngay sau khi reset component, việc gửi biểu mẫu có thể được cho qua
    • Lý do là dù giá trị rỗng, mã xác thực chưa được chạy trước khi sự kiện thay đổi xảy ra
    • Để xử lý cả giá trị ban đầu, cùng một phép xác thực cũng phải được chạy tại thời điểm component mount

Boilerplate tăng lên trong component khai báo

  • Khi xử lý cả xác thực giá trị ban đầu, mã nhanh chóng trở nên lặp lại và bất tiện
  • Đặc biệt phát sinh ba vấn đề
    • Logic xác thực bị lặp lại trong handler onChange và giai đoạn render ban đầu
    • Mã xác thực ban đầu nằm tách khỏi phần tử input, làm giảm tính kết dính và tạo rủi ro chỉ sửa một phía
    • Tổ hợp useRef, useLayoutEffect, onChange trở nên quá mức khi số lượng input tăng lên, và càng gây rối hơn khi chỉ một số input dùng customValidity
  • Sự phức tạp này nổi bật khi xử lý một API mệnh lệnh thuần túy trong component khai báo
  • CustomValidity không có thuộc tính input nào để đặt giá trị theo kiểu khai báo như các thuộc tính xác thực native
  • Nếu API rườm rà, mức độ áp dụng có thể thấp dù tính năng mạnh; đây là nguyên nhân cốt lõi khiến xác thực biểu mẫu native chưa được tận dụng nhiều

Mảnh ghép còn thiếu: thuộc tính custom-validity

  • Hình thái cần thiết là một thuộc tính khai báo như custom-validity, có thể chỉ định trực tiếp trên input
  • Trong framework khai báo, thuộc tính này cho phép đặt trạng thái xác thực gần phần tử input
  • Hiện tại HTML Spec chưa có custom-validity thực sự
  • Có thể mô phỏng hành vi này bằng một triển khai ở userland cho mục đích demo
  • Một triển khai hoàn thiện hơn được cung cấp làm ví dụ component dùng cho production

Xác thực bất đồng bộ và phụ thuộc giữa các input

  • Việc xác thực trong ứng dụng thực tế có thể phức tạp hơn kiểm tra cục bộ
  • Input tên người dùng phải kiểm tra với server xem tên đó đã được dùng hay chưa, và trong lúc đang request, biểu mẫu không nên ở trạng thái valid
  • Ví dụ dùng required để chặn input rỗng, đồng thời dùng customValidity để đưa input về trạng thái invalid tùy theo trạng thái loading và kết quả phản hồi
  • Phần triển khai gồm hai phần
    • Quản lý trạng thái request kiểm tra tính duy nhất của tên người dùng bằng useQuery của react-query
    • Dùng component <Input /> tùy chỉnh có thể nhận prop customValidity
  • Cách này có thể biểu diễn toàn bộ luồng xác thực bất đồng bộ, gồm trạng thái loading, lỗi và thành công, trong một thuộc tính duy nhất
  • Ví dụ bổ sung là một biểu mẫu yêu cầu nhập lại mật khẩu đã nhập, xử lý xác thực các trường input phụ thuộc lẫn nhau

Kết luận

  • setCustomValidity là một công cụ mạnh có thể xử lý nhiều nhu cầu xác thực khác nhau
  • Điều quyết định mức độ sử dụng thực tế không chỉ là sự tồn tại của tính năng, mà còn là API giúp dùng tính năng đó dễ dàng đến đâu
  • Một abstraction khai báo như custom-validity giúp sử dụng xác thực biểu mẫu native một cách tự nhiên hơn
  • Có thể kỳ vọng một ngày nào đó tính năng như vậy sẽ được đưa vào đặc tả HTML dưới dạng native

1 bình luận

 
GN⁺ 2024-10-29
Ý kiến trên Hacker News
  • Lần cuối tôi kiểm tra, các trình duyệt web hiện nay vẫn không thể tùy biến giao diện của thông báo kiểm tra hợp lệ HTML tích hợp sẵn https://stackoverflow.com/questions/5328883/how-do-i-style-t...
    Nếu Chrome và Firefox ít nhất còn tuân theo hướng dẫn UI của nền tảng OS để trông như thông báo do hệ thống hiển thị, kiểu tooltip title="", thì đã đỡ hơn; nhưng Chrome lại dùng biểu tượng vàng/cam, nền trắng chữ đen và bong bóng thoại bo góc cố định, nên xung đột nghiêm trọng với thẩm mỹ của dự án hiện tại
    Chrome trước đây từng cho phép tùy biến thông báo kiểm tra hợp lệ bằng bộ chọn giả phần tử có tiền tố nhà cung cấp, nhưng sau khi gỡ tính năng đó thì không mang trở lại nữa. Nó bị đưa vào danh sách những điều bực mình lặt vặt kiểu “cho tôi combobox HTML native đi”, “tại sao đến giờ vẫn là cái hộp Ctrl+click khó dùng chứ không phải danh sách checkbox”

    • Vấn đề ở đây không hẳn là thiếu khả năng tùy biến style tự thân, mà là việc đọc trạng thái validity native của input rồi render theo ý muốn thật ra khá dễ
      Vấn đề thực sự là khó đăng ký theo dõi chính xác các thay đổi trạng thái hợp lệ này. Có các sự kiện về tính hợp lệ, nhưng chúng không phải lúc nào cũng phát sinh. Nếu thay đổi trạng thái form bằng chương trình như gọi form.reset() hoặc input.value = '...', các sự kiện này sẽ không được kích hoạt
      Tôi nghĩ đây là một chủ đề hay để điều tra riêng và đề xuất cho nền tảng web
    • Tôi không hiểu lắm vì sao người ta lại muốn tùy biến style cả những thứ này. Thể hiện bằng màu sắc hay layout thì tốt, nhưng đến một lúc nào đó tính dễ dùng quan trọng hơn branding
    • Đúng vậy. Tuy nhiên, vẫn có thể ẩn thông báo mặc định và thay bằng thông báo tự tạo. Dù vậy vẫn giữ được lợi ích của kiểm tra hợp lệ form
    • Theo nghĩa đó, tùy biến style cho select đơn cũng không dễ như lẽ ra nó nên thế
  • Thứ lớn nhất, dễ triển khai nhất nhưng vẫn ít được dùng là sử dụng các giá trị thuộc tính type cụ thể như email, number, url
    Trên mobile, nó có thể bật bàn phím tối ưu và cải thiện trải nghiệm người dùng đáng kể

    • Tôi tránh type=number, thay vào đó dùng type=text inputmode=numeric. Nó không kèm các nút mũi tên mà đa số người dùng không cần khi nhập số, và trên iOS bàn phím cũng tốt hơn
    • Có nhiều nơi đáng ngạc nhiên là trên form đăng nhập ghi “email” nhưng lại không đặt đúng type
    • Tôi cũng thấy rất nhiều trường hợp như vậy với input date. Mỗi thư viện frontend lại có widget ngày tháng riêng, và nhiều cái trông rất tệ trên màn hình nhỏ
      Chỉ vì một widget đó mà phải thêm JS và CSS, một số còn phụ thuộc vào jQuery. Tất nhiên cũng có những widget có rất nhiều tùy chọn, nhưng với chi phí rất nhỏ, bạn có thể có một widget trông ổn ở mọi nơi, giống native, thường đáp ứng được yêu cầu, rồi có thể quên nó đi mà không phải lo cập nhật hay CDN
    • Đáng tiếc là input number còn thiếu sót và không nhất quán giữa các trình duyệt. Cuối cùng tôi luôn quay lại dùng kiểm tra hợp lệ bằng JavaScript
    • Gần đây tôi đã phải đảm bảo không dùng các phần tử input phức tạp hơn. Lý do là vì cần kiểm soát việc nhập bằng bàn phím ảo được triển khai trong trang
      Input thông thường còn miễn cưỡng làm được, còn các input đặc biệt hỗ trợ ít sự kiện hơn
  • Sản phẩm của tôi không vượt qua được kiểm toán khả năng tiếp cận vì dùng xác thực form HTML native, và khuyến nghị chính thức là hãy triển khai một lớp xác thực riêng. Tôi cũng đồng ý với khuyến nghị đó
    Xác thực HTML native có rất nhiều khiếm khuyết, và nói thật, tùy biến giao diện còn chưa phải nỗi lo lớn nhất. Dù vậy, nó cũng gần như chiếc đinh cuối cùng đóng vào quan tài
    Ví dụ, nếu muốn hiển thị nhiều lỗi cho mỗi trường cùng lúc thì cách duy nhất là nối chuỗi. Kiểu như “Cần có số. Cần có ký hiệu. Phải dài hơn 10 ký tự”, vừa tệ về trải nghiệm người dùng vừa không tốt cho khả năng tiếp cận. Vì trong accessibility tree, không thể điều hướng qua chuỗi đã bị nối như vậy. Đây không phải vấn đề của từng implementation, mà là vấn đề của chính đặc tả. Người dùng không thấy vui khi phải chơi trò đập chuột chũi với lỗi xác thực, nên cần có khả năng hiển thị nhiều lỗi cùng lúc
    Việc phụ thuộc vào trình duyệt cũng tệ. Bạn không kiểm soát được, mà implementation nhìn chung cũng rất dở. Chrome hiển thị popup khi focus; nó là popup, trông như modal, và không thể hiển thị tất cả lỗi form cùng lúc, nên bản thân nó đã không tốt cho khả năng tiếp cận. Không hiển thị thông tin quan trọng bằng popup là điều cơ bản trong accessibility, nhưng trình duyệt cũng không có nhiều cách khác nếu không can thiệp vào tài liệu thật
    Các lỗi ở cấp toàn bộ form không thuộc về một trường cụ thể vẫn cần xác thực tùy chỉnh. Ví dụ lỗi kiểu “Trường A và B không thể cùng tồn tại”; đã vậy thì tốt hơn là có một cách xác thực nhất quán
    Nếu có input tùy chỉnh không khớp với các kiểu input native, để giữ tính nhất quán bạn phải đặt thêm input ẩn, và việc này cũng phá vỡ accessibility. Muốn sửa thì cuối cùng cũng khó ngang với việc tự xây một hệ thống xác thực thân thiện với khả năng tiếp cận
    API customValidity mang tính mệnh lệnh và khó dùng. Trừ khi bạn muốn những thông báo tệ hại như “Trường này không hợp lệ”, gần như không có lựa chọn nào khác ngoài dùng custom validity. Vì vậy xác thực form HTML rất tệ

    • Đúng là khá trớ trêu khi tính năng do trình duyệt cung cấp lại có thể không vượt qua được yêu cầu về khả năng tiếp cận. Vì chúng ta luôn được dạy rằng một trong những động lực để dùng platform và tuân theo các phần tử ngữ nghĩa là accessibility
      Dù vậy, tôi vẫn nghĩ cơ chế xác thực native có giá trị để tận dụng. Không nhất thiết phải dùng tooltip xác thực native cho thông báo lỗi; có thể tự đọc ValidityState từ input.validity, rồi render thông báo theo cách mình muốn và hiển thị nhiều lỗi nếu cần
      Trình duyệt có thể được cải thiện, và nếu dùng cách tiếp cận chuẩn hóa thì ta có thể hưởng lợi từ các cải tiến đó. Kết luận kiểu “nếu không dùng popup thì accessibility bị hỏng” nghe có vẻ lạ, nhưng nếu cần đáp ứng kiểm toán thì có thể phải đi theo hướng đó
      Cũng có kỹ thuật để xử lý lỗi không thuộc về một trường cụ thể. Trong dự án của tôi, chúng tôi dùng component HiddenValidationInput, tạo ra một input chỉ đọc không hiển thị để render các lỗi tùy chỉnh không thuộc về trường nào khác. Chỉ cần render có điều kiện nên thực tế khá dễ dùng
      Tôi hoàn toàn đồng ý rằng API customValidity mang tính mệnh lệnh và rườm rà. Tôi đã viết một bài về đúng phần đó, và hy vọng phần này cũng sẽ được cải thiện theo thời gian
    • Thú vị đấy, nhưng trong app của tôi, tôi triển khai toàn bộ những xác thực đó. Xác thực toàn bộ form được xử lý ở server. Về cơ bản là có nhiều lớp xác thực và tận dụng mọi thứ có thể
      Thiết kế thô kệch và kém accessibility của Chrome là vấn đề của Chrome, nên tôi sẽ gửi bug report
      “Đặc tả” ở đây có phải là cái này không? https://html.spec.whatwg.org/multipage/dom.html#concept-elem...
      Tôi không thấy phần nào định nghĩa cách hiển thị thông báo xác thực. Thậm chí cũng không có nội dung nói rằng bắt buộc phải có thông báo
    • Tôi tò mò không biết vì sao các auditor lại đánh giá như vậy
  • Nói thật, những người viết các đặc tả như thế này có vẻ xa rời thực tế và không thực sự dùng những thứ họ đã đặc tả. Nó hoạt động với những thứ rất đơn giản, nhưng khi form bắt đầu phát triển, cuối cùng bạn sẽ nhận ra tốt hơn là tự viết tất cả

    • Đúng vậy. Chỉ cần một việc khá phổ biến là tham chiếu chéo với trường khác thì gần như lập tức cần JS. Ví dụ, nếu người dùng đã chỉ định quốc gia thì có thể xác thực mã bưu chính vừa nhập, còn nếu chưa thì phải đợi họ chọn quốc gia
      Một khi đã bắt đầu dùng JS, làm mọi thứ bằng code sẽ dễ hơn nhiều so với việc loay hoay với các thuộc tính xác thực
    • Đúng. Nó rất tuyệt cho đến khi bạn cần một date picker đa trình duyệt; từ thời điểm đó trở đi, bạn phải tự triển khai rất nhiều thứ. Sau từng ấy năm mà form HTML vẫn sơ khai như vậy thật bực mình
    • Phần lớn chức năng form là từ đầu thập niên 90. Có thể chúng ta không làm việc trong cùng thiên niên kỷ với một số người viết đặc tả
  • Nếu checkbox có nhãn, tôi mong nhãn được gắn thuộc tính for để có thể bật/tắt checkbox bằng cách bấm vào nhãn. Cá nhân tôi thấy đây là một trong những điều khó chịu nhất, có thể chỉ mình tôi vậy thôi

    • Bọc input bằng label cũng hoạt động. Tôi không hiểu vì sao mọi người có xu hướng tách hai thứ này ra
      Và tôi cũng không hiểu vì sao trình duyệt lại bắt đầu tách chúng ra. Theo tôi, không phải văn bản chứa checkbox và radio, mà checkbox và radio nên chứa văn bản
    • Không chỉ mình bạn đâu. Trên các trang web có khả năng tiếp cận tuân theo ADA/WCAG, đây là chức năng cần thiết
  • Có một ví dụ đơn giản không dùng React ở đây
    https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectE...

    • Tôi thấy rất kỳ lạ khi nói về xác thực HTML chuẩn mà tất cả ví dụ lại được trình bày bằng React. Nếu muốn dạy cách tiêu chuẩn hoạt động, không nên giả định React là mặc định
    • Giờ có vẻ hầu hết đều có thể làm được chỉ bằng CSS. Có thể chỉ cần JavaScript để ngăn popup mặc định xuất hiện
  • Tính năng kiểm tra hợp lệ của form HTML rất tuyệt. Chỉ có điều có một cái bẫy rất lớn
    Nó không hoạt động trên Firefox cho Android
    https://bugzilla.mozilla.org/show_bug.cgi?id=1510450

    • Tôi dùng Firefox trên mọi thiết bị di động, nhưng trong vấn đề này khó mà trách các nhà phát triển vì họ bỏ qua Firefox cho Android. Đây là một API mà mọi trình duyệt khác đã cho hoạt động từ 10 năm trước, và trách nhiệm dọn dẹp mớ hỗn loạn này thuộc về đội Firefox
      Không đáng để bỏ qua chuẩn chỉ vì chưa tới 1% người dùng không xem được thông báo lỗi của control được đánh dấu màu đỏ. Càng nhiều website dùng tính năng này, áp lực buộc Mozilla sửa trình duyệt càng lớn
      Đây không phải là một API kiểu WebMIDI do Chrome hay Safari triển khai trước khi chuẩn hóa, mà vốn là một phần của đặc tả HTML5 ban đầu
    • Firefox cho Android có tệp người dùng nhỏ hơn Samsung Internet hay Opera, chỉ khoảng 0,5%. Dành thời gian hỗ trợ nó gần như là lãng phí
      Điều đó càng đúng nếu nghĩ đến việc người ta dành ít thời gian đến mức nào để giúp những người dùng phần mềm hỗ trợ tiếp cận có thể sử dụng site đúng cách. Nếu chưa sẵn sàng nói đến cả UC Browser, tôi nghĩ vấn đề kiểu này không đáng được nhắc nhiều
    • Với tư cách người dùng Firefox hằng ngày trên Android, điều đau nhất là không theo kịp tiêu chuẩn. Đặc biệt là các vấn đề liên quan đến WebGL như [1] và những bất tiện nhỏ như [2]
      Dù vậy, việc có thể dùng uBlock Origin cùng các tiện ích mở rộng khác vẫn là một lợi thế rất mạnh
      [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1884282
      [2] https://bugzilla.mozilla.org/show_bug.cgi?id=1897707
    • Nó tệ hơn nhiều so với “không hoạt động”. Việc kiểm tra hợp lệ có chạy, nhưng hoàn toàn không hiển thị lỗi
      Nếu việc kiểm tra hợp lệ hoàn toàn chưa được triển khai thì có khi còn đỡ hơn; còn cái này thì thật sự là thảm họa. Tôi phát hiện ra sau một lần debug dài và đau đớn vài năm trước, và tôi chắc mình không phải người đầu tiên hay cuối cùng gặp chuyện này
    • Gần đây sau khi chuyển sang Firefox trên Android tôi mới nhận ra điều này. Khi đang làm một ứng dụng, dù cố gửi một trường bắt buộc còn trống, đúng nghĩa là chẳng có gì hiện ra cả
      Trước khi tìm kiếm, tôi không thể tưởng tượng mình đã bỏ sót điều gì, và khá sốc. Tự làm phần kiểm tra hợp lệ thì cũng được, nhưng cái này phải hoạt động mới đúng
  • Cần cẩn thận để không dùng quá đà
    Gần đây tôi cố xin hoàn tiền trên Groupon. Lý do là doanh nghiệp nơi tôi mua Groupon đã đổi ban điều hành mới và không chấp nhận Groupon của tôi
    Form có điều kiện “tối thiểu 15 từ”, nhưng làm thế nào cũng không vượt qua được kiểm tra hợp lệ, nên cuối cùng tôi phải inspect HTML
    \w là ký tự từ, \b là ranh giới từ, \s là khoảng trắng, và dấu câu thì đúng nghĩa là hoàn toàn không được phép

    • Tôi nghĩ đây không hẳn là vấn đề chỉ riêng kiểm tra hợp lệ của HTML. Chuyện tương tự xảy ra với bất kỳ loại kiểm tra hợp lệ nào. Cùng quy tắc đó cũng có thể đã được áp dụng trên server, và nếu vậy thì hết hy vọng
    • Đây cũng là một bằng chứng tốt cho ý tôi định nói. Các thuộc tính kiểm tra hợp lệ sẵn có như pattern thì hay, nhưng không đủ
      Ví dụ, ví dụ “nhập lại mật khẩu” có thể triển khai bằng thuộc tính pattern mà không cần setCustomValidity. Muốn vậy phải xây dựng động biểu thức chính quy từ giá trị nhập đầu tiên
      Tôi không so sánh các cách giải vì sợ bài viết quá dài, nhưng điểm chính là dùng customValidity giúp việc kiểm tra hợp lệ rõ ràng và dễ đọc hơn nhiều. Ở đây một API tốt hơn tạo ra khác biệt lớn
      Ràng buộc “tối thiểu 15 từ” cũng có thể được diễn đạt dễ nhìn hơn nhiều, kiểu như value.split(/\s+/).length >= 15
  • Việc ít được dùng là có lý do. Nhiều framework và thư viện cung cấp chức năng kiểm tra hợp lệ vững chắc và có thể tùy biến style, một số còn rất tinh vi và mở rộng được. Nếu không cần tự làm khổ mình thì tốt nhất đừng tự hành hạ bản thân

    • Dù sao thì cũng phải tự triển khai kiểm tra hợp lệ ở backend. Luôn có người cố đụng vào form bằng trình duyệt kỳ lạ, curl, hoặc công cụ khác không có sẵn cùng kiểu kiểm tra hợp lệ cho form
      Không thể tin rằng client đã kiểm tra hợp lệ, hay đã kiểm tra đúng, nên backend vẫn phải kiểm tra dữ liệu nhập và có khả năng hiển thị lại form kèm lỗi kiểm tra hợp lệ cho tất cả các trường
      Kiểm tra hợp lệ ở frontend chỉ nhằm giúp người dùng. Nhưng nếu muốn styling hoặc kích hoạt từ backend khi submit, cuối cùng vẫn phải tự triển khai phần styling
    • Đồng ý. Khi có thể tôi cố dùng các tính năng chuẩn của trình duyệt, nhưng kiểm tra hợp lệ tích hợp sẵn thì sau khi xem xét chưa bao giờ thấy đáng dùng
      Có quá nhiều cạm bẫy, và để hỗ trợ dễ dàng các phép kiểm tra phức tạp hơn thì cuối cùng vẫn dùng thư viện
      Hơn nữa, khi dùng thư viện, tùy trường hợp còn có khả năng chia sẻ một phần mã kiểm tra hợp lệ giữa frontend và backend
      Đặc biệt bài này trông như đang né một vấn đề bằng useLayoutEffect, mà đó không phải việc nên làm qua loa
  • Một điều tôi không thích ở kiểm tra hợp lệ của form HTML là nó chạy ngay từ lúc tải trang. Ví dụ, nếu gắn style trạng thái lỗi vào đây, form sẽ được tải lên trong tình trạng đầy lỗi ngay từ đầu, trông có thể gây áp lực cho người dùng

    • Có pseudo-class :user-invalid giúp tránh điều này ở mức nào đó. Tuy nhiên nó có phần thiếu linh hoạt, nên tùy use case có thể vẫn chưa đủ
      https://developer.mozilla.org/en-US/docs/Web/CSS/:user-inval...
    • Đây là một trong những lý do chính khiến mọi người bắt đầu dùng JavaScript: để chỉ hiển thị lỗi sau khi form đã bị “đụng vào” hoặc ngay trước khi submit
    • Tôi chưa bao giờ hiểu vì sao trải nghiệm này lại được chọn làm mặc định. Phần lớn người dùng không thích việc mọi phần tử form như đang quát vào mặt họ khi họ còn chưa có cơ hội làm gì
      Có thể dùng script để né, nhưng đến lúc đó thì tính năng này cũng chẳng giúp được gì nhiều. Tôi nghĩ đây chính là lý do lớn nhất khiến nó không được áp dụng rộng rãi hơn