Chuyển Đổi HTML sang JSX

Chuyển HTML sang JSX cho React. Đổi class→className, for→htmlFor, parse style string sang object, tự đóng void element, xử lý SVG attr.

Đầu Vào HTML
clearXóapasteDán
Đầu Ra JSX
Tùy Chọn
Bảng Tham Chiếu HTML → JSX
HTMLJSXGhi chú
class="x"className="x"JSX dùng className vì class là từ khóa dành riêng của JavaScript
for="x"htmlFor="x"JSX dùng htmlFor vì for là từ khóa dành riêng của JavaScript
tabindex="0"tabIndex="0"Tất cả HTML attribute dùng camelCase trong JSX
id="btn-f"onClick={f}Event handler nhận tham chiếu hàm, không phải chuỗi code
style="color:red"style={{color: 'red'}}Style JSX nhận object với khóa camelCase, giá trị là chuỗi hoặc số
<br><br />Mọi phần tử phải đóng đúng cách trong JSX (void element tự đóng)
<!-- c -->{/* c */}Biểu thức JavaScript trong JSX nằm trong {dấu ngoặc nhọn}
stroke-width="2"strokeWidth="2"Attribute trình bày SVG dùng camelCase trong JSX (nhưng viewBox, xmlns giữ nguyên)

Chuyển Đổi HTML sang JSX — JSX Sẵn Sàng Cho React Từ HTML Thuần

Dán bất kỳ snippet HTML nào và nhận JSX biên dịch sạch trong component React. Bộ chuyển đổi xử lý mọi khác biệt phổ biến: đổi class thành className và for thành htmlFor, parse chuỗi style thành object JavaScript với khóa camelCase, tự đóng void element, chuyển đổi attribute SVG có gạch nối, viết lại comment HTML thành biểu thức JSX, và bọc event handler trong arrow function. Tùy chọn bọc đầu ra trong Fragment hoặc function component đầy đủ, với thụt lề điều chỉnh được và ô nhập tên component.

Tại sao React không thể nhận HTML trực tiếp?

JSX là mở rộng cú pháp của JavaScript, không phải HTML — và JavaScript có từ khóa dành riêng xung đột với tên thuộc tính HTML. Hai cái lớn nhất là:

- **class** — đã dùng trong JavaScript cho khai báo class (`class MyComponent extends React.Component`).
- **for** — dùng trong vòng lặp for (`for (let i = 0; ...)`).

React đổi tên các thuộc tính đó thành **className** và **htmlFor** để né xung đột. Mọi đổi tên camelCase khác (tabIndex, readOnly, autoComplete…) theo cùng mẫu: JSX dùng camelCase cho thuộc tính DOM nhiều từ vì biểu thức JSX được đánh giá như literal object JavaScript, nơi không cho phép dấu gạch trong tên thuộc tính.

React 19 thực sự đã bắt đầu chấp nhận nhiều thuộc tính kiểu HTML (`tabindex`, `readonly`) tại runtime, nhưng linter và đa số quy ước code vẫn muốn dạng camelCase. Bộ chuyển này xuất camelCase nghiêm ngặt để tương thích React 16 đến 19.

Style được chuyển từ chuỗi sang object như thế nào?

Chuỗi style HTML là các cặp khóa-giá trị ngăn bởi dấu chấm phẩy:

```
style="margin-top: 16px; background: #eee; font-weight: 700;"
```

JSX cần một object JavaScript với khóa camelCase và giá trị là chuỗi hoặc số:

```
style={{ marginTop: '16px', background: '#eee', fontWeight: 700 }}
```

Bộ chuyển tách theo dấu chấm phẩy, tách mỗi cặp tại dấu hai chấm đầu tiên, chuyển tên thuộc tính sang camelCase (`margin-top` → `marginTop`), và quyết định có đặt dấu nháy quanh giá trị. Giá trị thuần số (`16`, `700`, `1.5`) phát ra không nháy — React coi giá trị số cho thuộc tính kích thước ngầm là px. Mọi thứ khác được nháy như chuỗi.

Vài hành vi tinh tế:

- Custom property CSS (`--my-var`) giữ dấu gạch — được nháy như khóa chuỗi: `'--my-var': 'value'`.
- `!important` bị bỏ (style JSX không hỗ trợ nguyên gốc; dùng class CSS thực thay).
- Vendor prefix cũng camelCase: `-webkit-transform` → `WebkitTransform` (chú ý chữ W viết hoa, theo quy ước React).

Nếu bạn muốn dán style như chuỗi thô và không chuyển, bỏ chọn 'Chuyển style attr sang object' — JSX chấp nhận như chuỗi, dù đa số linter React phàn nàn.

Bộ chuyển xử lý event handler như onclick thế nào?

Trong HTML, thuộc tính event handler chứa chuỗi JavaScript mà trình duyệt sẽ eval khi event nổ:

```
<button onclick="track('signup'); openModal()">Sign up</button>
```

Event handler JSX cần tham chiếu hàm (hoặc arrow function inline), không phải chuỗi. Bộ chuyển bọc code gốc trong arrow function để vẫn chạy:

```
<button onClick={() => { track('signup'); openModal() }}>Sign up</button>
```

Đây cố ý là bọc theo nghĩa đen — bảo toàn logic hiện có để snippet biên dịch, nhưng bạn thường sẽ muốn refactor thành handler có tên:

```
<button onClick={handleSignup}>Sign up</button>
```

Tùy chọn 'Loại bỏ event handler' xóa hoàn toàn handler inline nếu bạn muốn tự gắn trong file JSX. Hữu ích khi migrate markup cũ có handler inline khắp nơi.

Việc đổi tên thuộc tính tự nó cơ học: `onclick` → `onClick`, `onmouseover` → `onMouseOver`, `oninput` → `onInput`, v.v. Bộ chuyển nhận diện bất kỳ thuộc tính `on[a-z]+` nào là event handler.

Tại sao đôi khi tôi thấy {'{'} và &lt; trong output?

JSX được parse như JavaScript, nên các ký tự `{`, `}`, `<`, và `>` có ý nghĩa cú pháp trong markup:

- `{` mở biểu thức JavaScript
- `<` mở thẻ JSX

Nếu các ký tự đó xuất hiện trong nội dung văn bản, JSX coi là code, không phải văn bản. Bộ chuyển escape chúng để React render thành ký tự nghĩa đen:

- `{` nghĩa đen trở thành `{'{'}`
- `}` trở thành `{'}'}`
- `<` trở thành `&lt;` (entity HTML, mà JSX giữ trong nội dung văn bản)
- `>` trở thành `&gt;`

Điều này quan trọng nhất cho khối hiển thị code. Nếu bạn dán `<code>const x = { a: 1 };</code>`, output JSX sẽ đọc `<code>const x = {'{'} a: 1 {'}'};</code>` — xấu nhưng đúng chức năng.

Cho production, dùng component highlight cú pháp chuyên dụng (Prism, Shiki, Highlight.js) hoặc bọc code đen trong `<pre>{`code đây`}</pre>` với template literal — biểu thức JSX có thể chứa bất kỳ chuỗi nào. Việc escape của bộ chuyển là fallback an toàn khi bạn không muốn refactor.

Bộ chuyển làm gì với SVG attribute?

SVG có hàng chục thuộc tính trình bày dùng gạch nối: `stroke-width`, `fill-opacity`, `text-anchor`, `font-family`, v.v. Trong JSX tất cả cần camelCase: `strokeWidth`, `fillOpacity`, `textAnchor`, `fontFamily`.

Bộ chuyển nhận diện danh sách chuẩn các thuộc tính SVG có gạch nối (khoảng 35, theo React DOM API) và chỉ chuyển những cái đó — thuộc tính `data-*` và `aria-*` luôn giữ dấu gạch vì JSX cho phép dấu gạch đặc biệt trong hai namespace đó.

Vài thuộc tính SVG *đã* là camelCase trong HTML và giữ nguyên: `viewBox`, `preserveAspectRatio`, `gradientUnits`, `xmlns`. Đặc tả HTML5 định nghĩa những cái này là phân biệt hoa thường CamelCase, và JSX kế thừa.

Một snippet SVG đầy đủ từ thư viện icon điển hình — path, transform, gradient — chuyển sạch trong một lần dán. Log biến đổi cho thấy thuộc tính nào đã đụng để bạn phát hiện bất thường.

Nên bọc đầu ra trong Fragment hay component?

Chọn dựa vào markup đi đâu:

- **Không bọc** — bộ chuyển xuất JSX thô bạn có thể dán đâu cũng được. Tốt nhất khi tích hợp vào return statement của component có sẵn.
- **Fragment (`<></>`)** — bọc nhiều phần tử cấp đỉnh trong React Fragment. Dùng khi HTML có hơn một root (ví dụ hai div anh em); JSX yêu cầu một root duy nhất, và Fragment không thêm phần tử bọc vào DOM.
- **Function component** — bọc mọi thứ trong định nghĩa `function MyComponent() { return (...); }` đầy đủ. Tốt nhất cho scaffolding nhanh khi bắt đầu file component mới từ mockup thiết kế.

Ô tên component chỉ được dùng trong chế độ component. Bị giới hạn ký tự alphanumeric và phải bắt đầu bằng chữ hoa (quy ước React — component phải bắt đầu chữ hoa để JSX phân biệt với thẻ HTML).

Không chế độ bọc nào tiêm `import React from 'react'` — React hiện đại (17+) với JSX transform không cần. Nếu bạn dùng React cũ, thêm import thủ công.

Còn các React DOM attribute tôi mong nhưng không thấy ở đây?

Bộ chuyển xử lý trường hợp phổ biến. Vài thuộc tính có sắc thái đáng biết:

- **value vs defaultValue** — Trong HTML, `<input value="x">` đặt giá trị ban đầu. Trong JSX, đó tạo input *controlled* phải có onChange. Nếu muốn hành vi HTML (giá trị ban đầu, rồi user có thể sửa), dùng `defaultValue="x"`. Bộ chuyển để `value` yên — bạn cần quyết định controlled vs uncontrolled tùy trường hợp.
- **checked vs defaultChecked** — Cùng phân biệt controlled/uncontrolled cho checkbox/radio.
- **selected trên `<option>`** — Dùng `value` trên `<select>` cha thay vì, đó là cách dùng React.
- **dangerouslySetInnerHTML** — Cách duy nhất của React để set HTML trực tiếp. Bộ chuyển không sinh; nó chuyển nội dung văn bản thành node văn bản JSX thay vì.
- **ref** — Prop dành riêng React mà bộ chuyển không sinh; thêm thủ công khi nối focus hay đo DOM.

Bộ chuyển xử lý migrate *cú pháp* — đưa HTML của bạn biên dịch như JSX. Migrate *ngữ nghĩa* (controlled input, ref, state) là thứ bạn lớp lên trên tùy vào component cần làm gì.

Bộ chuyển này có riêng tư không?

Có. Việc chuyển đổi diễn ra hoàn toàn trong trình duyệt:

- Trang dùng DOMParser tích hợp của trình duyệt để parse HTML — không API ngoài nào được gọi.
- Quy tắc biến đổi là code JavaScript chạy cục bộ.
- Nút Mẫu điền textarea với chuỗi sẵn; không gì được tải về.
- Nút Sao Chép dùng API clipboard của trình duyệt.
- Không telemetry về HTML bạn dán.

Xác minh bằng DevTools → Network và quan sát panel khi bạn bấm Chuyển — không request nào nổ. Điều này cũng có nghĩa công cụ hoạt động offline sau khi trang đã tải, nên bạn có thể chuyển snippet markup tại khách sạn, trên máy bay, hay sau firewall công ty mà không lo code đi đâu.

Tính Năng Chính

  • DOMParser của trình duyệt để parse HTML mạnh mẽ (xử lý markup hỏng/không đóng tốt)
  • Đổi tên class → className và for → htmlFor
  • tabindex → tabIndex, readonly → readOnly, và 25+ ánh xạ camelCase khác
  • Event handler (onclick, onchange, v.v.) đổi tên camelCase và bọc trong arrow function
  • Chuỗi style inline parse thành object JavaScript với khóa camelCase
  • Attribute SVG có gạch nối (stroke-width, fill-opacity, text-anchor) chuyển sang camelCase
  • Void element (br, img, input) tự đóng cho JSX strict mode
  • Comment HTML chuyển thành biểu thức JSX {/* ... */}
  • Boolean attribute (disabled, checked, required) phát ra không kèm giá trị
  • Attribute data-* và aria-* giữ nguyên theo đặc tả JSX
  • Ba chế độ bọc: không, Fragment, hoặc function component đầy đủ
  • Thụt lề điều chỉnh được: 2 khoảng trắng, 4 khoảng trắng, hoặc tab
  • Ô nhập tên component cho chế độ function component
  • Tùy chọn loại bỏ event handler cho migrate sạch
  • Log biến đổi cho thấy chính xác cái gì đã đổi
  • JavaScript thuần — không thư viện ngoài
  • Hoạt động offline sau lần tải đầu
  • 100% phía client — HTML của bạn ở trong trình duyệt