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. 네, 많은 기업에서 사용하고 있습니다. 특히 콘텐츠 중심 사이트에 적합합니다.