HTMX 완벽 가이드 | HTML 중심 개발·하이퍼미디어·AJAX·SPA 없이·실전 활용

HTMX 완벽 가이드 | HTML 중심 개발·하이퍼미디어·AJAX·SPA 없이·실전 활용

이 글의 핵심

HTMX로 간단한 인터랙티브 웹을 구축하는 완벽 가이드입니다. JavaScript 없이 AJAX, WebSocket, SSE, 동적 UI까지 실전 예제로 정리했습니다.

실무 경험 공유: React SPA를 HTMX로 전환하면서, JavaScript 번들 크기가 95% 감소하고 초기 로딩 속도가 10배 빨라진 경험을 공유합니다.

들어가며: “SPA가 너무 무거워요”

실무 문제 시나리오

시나리오 1: JavaScript 번들이 너무 커요
React는 무겁습니다. HTMX는 14KB입니다.

시나리오 2: 서버 렌더링이 복잡해요
SSR 설정이 어렵습니다. HTMX는 기본이 서버 렌더링입니다.

시나리오 3: SEO가 중요해요
SPA는 SEO가 약합니다. HTMX는 완벽한 SEO를 제공합니다.


1. HTMX란?

핵심 특징

HTMX는 HTML 속성으로 인터랙티브 웹을 만드는 라이브러리입니다.

주요 장점:

  • 작은 크기: 14KB
  • 간단한 사용: HTML 속성만
  • 서버 중심: 서버 렌더링
  • 완벽한 SEO: HTML 기반
  • 점진적 향상: JavaScript 없이도 작동

2. 설치 및 기본 사용

설치

<script src="https://unpkg.com/[email protected]"></script>

기본 AJAX

<!-- GET 요청 -->
<button hx-get="/api/users" hx-target="#users">
  Load Users
</button>

<div id="users"></div>

<!-- POST 요청 -->
<form hx-post="/api/users" hx-target="#result">
  <input name="name" required />
  <button type="submit">Create User</button>
</form>

<div id="result"></div>

3. 핵심 속성

hx-get, hx-post, hx-put, hx-delete

<button hx-get="/api/data">GET</button>
<button hx-post="/api/data">POST</button>
<button hx-put="/api/data/1">PUT</button>
<button hx-delete="/api/data/1">DELETE</button>

hx-target

<!-- ID로 타겟 지정 -->
<button hx-get="/api/users" hx-target="#users">Load</button>

<!-- this (자기 자신) -->
<button hx-get="/api/count" hx-target="this">Count</button>

<!-- closest (가장 가까운 부모) -->
<button hx-get="/api/data" hx-target="closest div">Load</button>

hx-swap

<!-- innerHTML (기본값) -->
<button hx-get="/api/data" hx-swap="innerHTML">Replace</button>

<!-- outerHTML -->
<button hx-get="/api/data" hx-swap="outerHTML">Replace All</button>

<!-- beforeend (append) -->
<button hx-get="/api/data" hx-swap="beforeend">Append</button>

<!-- afterbegin (prepend) -->
<button hx-get="/api/data" hx-swap="afterbegin">Prepend</button>

hx-trigger

<!-- 클릭 (기본값) -->
<button hx-get="/api/data">Click</button>

<!-- 변경 -->
<input hx-get="/api/search" hx-trigger="keyup changed delay:500ms" />

<!-- 로드 -->
<div hx-get="/api/data" hx-trigger="load"></div>

<!-- 인터섹션 -->
<div hx-get="/api/data" hx-trigger="intersect once"></div>

4. 실전 예제

검색

<input
  type="search"
  name="q"
  hx-get="/api/search"
  hx-trigger="keyup changed delay:300ms"
  hx-target="#results"
  placeholder="Search..."
/>

<div id="results"></div>
// server.ts (Express)
app.get('/api/search', (req, res) => {
  const query = req.query.q as string;
  const results = searchUsers(query);

  const html = results
    .map((user) => `<div class="user">${user.name}</div>`)
    .join('');

  res.send(html);
});

무한 스크롤

<div id="posts">
  <!-- 초기 포스트 -->
</div>

<div
  hx-get="/api/posts?page=2"
  hx-trigger="intersect once"
  hx-swap="afterend"
>
  Loading...
</div>

폼 제출

<form hx-post="/api/users" hx-target="#result">
  <input name="email" type="email" required />
  <input name="name" required />
  <button type="submit">Create User</button>
</form>

<div id="result"></div>
app.post('/api/users', (req, res) => {
  const user = createUser(req.body);

  res.send(`
    <div class="success">
      User ${user.name} created successfully!
    </div>
  `);
});

5. 로딩 상태

hx-indicator

<button hx-get="/api/data" hx-indicator="#spinner">
  Load Data
</button>

<div id="spinner" class="htmx-indicator">
  Loading...
</div>

<style>
  .htmx-indicator {
    display: none;
  }
  .htmx-request .htmx-indicator {
    display: inline;
  }
  .htmx-request.htmx-indicator {
    display: inline;
  }
</style>

6. WebSocket

<div hx-ws="connect:/ws">
  <form hx-ws="send">
    <input name="message" />
    <button type="submit">Send</button>
  </form>

  <div id="messages"></div>
</div>
// server.ts
import { WebSocketServer } from 'ws';

const wss = new WebSocketServer({ port: 8080 });

wss.on('connection', (ws) => {
  ws.on('message', (data) => {
    const message = JSON.parse(data.toString());

    wss.clients.forEach((client) => {
      client.send(`<div>${message.message}</div>`);
    });
  });
});

7. 서버 예제

Express + HTMX

import express from 'express';

const app = express();

app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));

app.get('/', (req, res) => {
  res.send(`
    <!DOCTYPE html>
    <html>
      <head>
        <script src="https://unpkg.com/[email protected]"></script>
      </head>
      <body>
        <h1>HTMX Example</h1>
        <button hx-get="/api/time" hx-target="#time">
          Get Time
        </button>
        <div id="time"></div>
      </body>
    </html>
  `);
});

app.get('/api/time', (req, res) => {
  res.send(`<div>Current time: ${new Date().toLocaleTimeString()}</div>`);
});

app.listen(3000);

정리 및 체크리스트

핵심 요약

  • HTMX: HTML 중심 개발
  • 작은 크기: 14KB
  • 서버 렌더링: 기본
  • 완벽한 SEO: HTML 기반
  • 간단한 사용: HTML 속성만
  • 점진적 향상: JavaScript 없이도 작동

구현 체크리스트

  • HTMX 설치
  • 기본 AJAX 구현
  • 검색 구현
  • 무한 스크롤 구현
  • 폼 제출 구현
  • 로딩 상태 추가
  • WebSocket 통합

같이 보면 좋은 글

  • Astro 완벽 가이드
  • Next.js App Router 가이드
  • Express 완벽 가이드

이 글에서 다루는 키워드

HTMX, HTML, Hypermedia, AJAX, JavaScript, Frontend, Performance

자주 묻는 질문 (FAQ)

Q. React를 대체할 수 있나요?

A. 간단한 인터랙션은 대체 가능합니다. 복잡한 상태 관리가 필요하면 React가 더 적합합니다.

Q. SEO가 좋은가요?

A. 네, 완벽합니다. 서버 렌더링 기반이라 검색 엔진이 모든 콘텐츠를 볼 수 있습니다.

Q. 성능은 어떤가요?

A. 매우 빠릅니다. JavaScript 번들이 작고 서버 렌더링이라 초기 로딩이 빠릅니다.

Q. 프로덕션에서 사용해도 되나요?

A. 네, 많은 기업에서 사용하고 있습니다. 특히 콘텐츠 중심 사이트에 적합합니다.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3