TreeMap
A free, open-source disk-space visualizer. Squarified treemap, duplicate hunting, disk-full forecasting, and cleanup that only ever moves files to the Trash.
법률문서(계약서·소장·고소장) 생성용 React 에디터 — 조항·번호 자동 매김, {{변수}}, 한글(hwp·hwpx)·Word(docx) 열기·저장
Translation pending
ProductivityTypeScript · CSSGitHub @hwondevOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Loading the full README. The saved excerpt is shown below.
계약서·합의서 같은 법률문서를 만드는 React 에디터입니다.Read the full README ↗
계약서·합의서 같은 법률문서를 만드는 React 에디터입니다.
갑 제1호증, 갑 제2호증… 증거를 중간에 넣거나 빼도 호증 번호가 알아서 다시 매겨지고, 본문의 (갑 제1호증) 참조도 따라 바뀌어요{{변수}} 채우기: 본문에 {{갑}}을 입력하면 입력칸이 생기고, 값을 넣으면 문서에 반영돼요.docx, .hwpx, .hwp(HWP 5.0)예요. .hwpx는 한글 2014 이상에서 열려요.doc(97–2003)는 열기만 돼요. 글자와 표만 옮기고 굵게 같은 글자 서식과 그림은 옮기지 않아요민법 제750조, 대법원 2016. 4. 28. 선고 2015다12345 판결, 2024가단157033 같은 인용을 알아보고 국가법령정보센터 링크를 붙여요 (API 키가 필요 없어요){{변수}} 빈칸이 들어간 상태로 바로 시작해요 (원고·신청인 / 피고 / 기타로 분류)금 37,200,000원이나 금 삼천칠백이십만 원정(₩37,200,000)으로 바꿔요에디터 엔진은 Tiptap(ProseMirror)을, 파일 변환은 docx·mammoth·hwp-convert를 씁니다.
npm i legal-doc-editor
import { LegalEditor } from 'legal-doc-editor'
import 'legal-doc-editor/style.css'
const template = `
<h1>비밀유지계약서</h1>
<p>{{갑}}과 {{을}}은 다음과 같이 계약을 체결한다.</p>
<h2>(목적)</h2>
<ol><li><p>첫째 항</p></li><li><p>둘째 항</p></li></ol>
`
export default function Page() {
return <LegalEditor content={template} onChange={(html) => save(html)} />
}
| 요소 | 의미 | 표시 |
|---|---|---|
h1 | 문서 제목 | 가운데 정렬 |
h2 | 조 | 제N조 |
h3 | 소제목 (청구취지·고소이유 등) | 가운데 정렬 |
p[data-num="1"~"4"] | 번호 문단 (소장식) | 1. → 가. → (1) → (가), 제목·조·소제목마다 1부터 |
p[data-evidence="갑"|"을"|"병"] | 호증 문단 (입증방법) | 갑 제1호증 → 갑 제2호증, 당사자별로 문서 전체에서 이어 셈. 번호 문단과 함께 쓰면 1. 갑 제1호증. data-evidence-start="5"면 그 문단부터 5로 시작 |
span[data-evidence-ref] | 본문 호증 참조 | 가리키는 호증 문단(data-evidence-id)의 현재 번호. data-form="short"는 제3호증, "number"는 3만. 증거가 없어지면 빨간 밑줄 |
table | 표 | 표 |
ol > li | 항 | ①, ② |
ol ol > li | 호 | 1., 2. |
span[data-var] 또는 {{이름}} | 변수 | 입력값 |
툴바 호증 버튼은 누를 때마다 갑 → 을 → 해제로 바뀌고, 호증 문단 끝에서 Enter를 누르면 다음 호증이 이어져요. 준비서면처럼 앞 서면에 낸 증거 다음 번호부터 적을 때는 첫 호증 문단에서 더보기(⋯)의 호증 시작 번호를 눌러 번호(예: 5)를 정하면 갑 제5호증, 갑 제6호증…으로 이어져요. 첫 호증을 지우거나 위에 호증을 새로 넣어도 시작 번호는 지금 첫 호증으로 옮겨가요. 파일을 열 때는 입증방법·증명방법·증거방법 소제목 아래의 갑 제N호증이 차례대로일 때만 호증 문단으로 바꿔요(첫 번호가 5면 5부터 시작하는 것으로 봐요). 갑 제1호증의 1 같은 가지번호나 내지로 묶은 줄은 글자로 둬요.
본문(청구원인 등)에 갑 제2호증을 입력하면 그 증거를 가리키는 참조로 바뀌어요(바로 Backspace를 누르면 글자로 돌아가요). 증거를 넣고 빼거나 잘라내 옮겨도 참조 번호가 따라 바뀌고, 가리키던 증거를 지우면 빨간 밑줄로 알려 줘요. 파일을 열 때도 자동 번호로 바꾼 증거가 있으면 본문의 갑 제N호증을 참조로 바꿔요. 갑 제1호증 내지 제3호증, 갑 제1호증, 제2호증, 갑 제1, 2호증 같은 범위·나열도 번호마다 자기 증거를 따라가요(갑 제1호증을 친 뒤 내지 제3호증을 이어 쳐도 돼요). 묶음 안에 문서에 없는 증거가 섞였거나 갑 제1, 2호증의 1처럼 번호 나열 뒤에 가지번호가 붙으면 글자로 두니 번호가 바뀌면 직접 고쳐 주세요.
본문에 적힌 인용을 알아보고 밑줄을 그어요. 마우스를 올리면 주소가 보이고, Ctrl(⌘)+클릭하면 국가법령정보센터에서 열려요 (읽기 전용일 때는 그냥 클릭).
| 형식 | 예 | 링크 |
|---|---|---|
| 판결·결정 | 대법원 2016. 4. 28. 선고 2015다12345 판결, 대법원 2020. 1. 9.자 2019마123 결정 | 판례 검색 |
| 사건번호 | 2015다12345, 2018노1234, 2024가단157033 | 판례 검색 |
| 법령 조문 | 민법 제750조, 형법 제347조 제1항, 특정경제범죄 가중처벌 등에 관한 법률 제3조 | 해당 조문 |
문서 데이터는 바뀌지 않아요. 화면에만 덧입히는 표시라서 onChange HTML, toPlainHtml, .docx·.hwpx 저장 결과는 인용이 없을 때와 똑같아요. 인쇄할 때도 밑줄이 빠져요.
날짜(2026. 9. 2.), 전화번호, 계좌번호는 인용으로 보지 않아요. 다만 인용 인식은 글자 모양만 보는 것이라 놓치거나 잘못 잡을 수 있고, 링크가 가리키는 조문이 실제로 맞는지는 직접 확인해 주세요.
**내보내기 → 한글 파일 (.hwp)**은 .hwpx를 만든 뒤 @rhwp/core(Rust→WASM, MIT)로 HWP 5.0 파일로 바꿔요.
WASM이 약 10MB라 처음 .hwp로 저장할 때만 불러와요. 에디터 본체 번들에는 들어가지 않아요.
Vite를 쓰면 사전 번들링이 WASM 경로를 잃지 않도록 제외해 주세요.
// vite.config.ts
export default defineConfig({ optimizeDeps: { exclude: ['@rhwp/core'] } })
그래도 WASM을 못 찾으면 node_modules/@rhwp/core/rhwp_bg.wasm을 정적 폴더에 복사하고 주소를 넘겨요: <LegalEditor hwpWasmUrl="/rhwp_bg.wasm" />
만든 파일은 다시 읽었을 때 제목·조항·번호·표·글자가 그대로인지 검사하지만, 한글 프로그램에서 열리는지는 직접 확인해 주세요.
| 묶음 | 버튼 | 설명 |
|---|---|---|
| 문단 | 본문 · 제목 · 소제목 · 조 | 선택 상자. 조를 고르면 제N조가 자동으로 붙어요 |
| 번호 | 1. · 가. · (1) · (가) · 항 | 소장식 번호 문단과 계약서의 항 ①② |
| 증거 | 호증 | 누를 때마다 갑 → 을 → 해제 |
| 넣기 | 빈칸 · 표 · 금액 | 빈칸은 오른쪽 입력값으로 채워요 |
| 글자 | 굵게 · 더보기(⋯) | 더보기: 금액을 한글로, 호증 시작 번호, 들여쓰기·내어쓰기 |
지금 커서가 있는 곳의 서식은 버튼이 남색으로 켜져 보여요. 오른쪽 끝의 열기로 파일을 열고, 내보내기에서 인쇄·PDF, 한글(.hwp·.hwpx), Word(.docx) 중 용도에 맞게 골라요.
화면 색과 글꼴은 CSS 변수(--le-*)로 정해져 있어요. 쓰는 쪽에서 덮어쓰면 돼요.
.le-root {
--le-accent: #0f5132; /* 주요 버튼·켜진 상태 (기본 남색 #1f3050) */
--le-brass: #b5832a; /* 빈칸 밑줄·진행 표시 (기본 황동 #a07c3b) */
--le-desk: #eceee9; /* 문서 뒤 바탕 */
--le-serif: 'Nanum Myeongjo', serif; /* 문서 본문 */
--le-sans: 'Pretendard', sans-serif; /* 화면 글자 */
}
기본 글꼴은 문서 본문 Noto Serif KR, 화면 글자 IBM Plex Sans KR이에요. 라이브러리는 글꼴 파일을 불러오지 않으니, 쓰려면 페이지에서 불러와 주세요(없으면 시스템 명조·고딕으로 보여요).
입력값·템플릿·조항 라이브러리·판례 검색은 오른쪽 패널에 섹션으로 모여 있어요. 섹션 제목을 누르면 접고 펼 수 있고(처음에는 모두 펼쳐져 있어요), 접은 섹션은 문서를 고쳐도 접힌 채로 있어요.
templates를 넘기면 오른쪽 패널에 템플릿 목록이 생겨요. 검색칸에서 이름으로 찾거나 분류 칩(전체·원고·신청인·피고·기타)으로 좁히고, 누르면 문서가 그 템플릿으로 바뀌어요. 작성 중인 내용이 있으면 먼저 물어보고, 바꾼 뒤에도 되돌리기(Ctrl·⌘+Z)로 돌아올 수 있어요. 입력값은 그대로 두어서 같은 이름의 빈칸({{원고 이름}} 등)에 이어서 쓰여요.
import { LegalEditor, templates } from 'legal-doc-editor'
<LegalEditor templates={templates} autoFees />
// 내 템플릿 더하기
<LegalEditor templates={[...templates, { id: 'my-notice', title: '통지서', category: '기타', description: '…', html: '<h1>통 지 서</h1><p>…</p>' }]} />
clauses를 넘기면 오른쪽 패널에 조항 목록이 생겨요. 분류 칩(전체·일반·기간·의무·책임·종료·분쟁)으로 좁히거나 검색칸에서 제목·분류로 찾고, 누르면 커서 위치에 조항이 들어가요. 전체에서는 분류별로 묶어 보여줘요. 조항 안의 {{변수}}는 입력칸에 바로 나타나고 뒤쪽 조 번호는 알아서 밀려요.
import { LegalEditor, clauses } from 'legal-doc-editor'
<LegalEditor clauses={clauses} />
// 내 조항 더하기
<LegalEditor clauses={[...clauses, { id: 'my-sla', title: '서비스 수준', category: '의무', html: '<h2>(서비스 수준)</h2><p>…</p>' }]} />
기본 조항: 목적, 계약기간(자동 연장), 비밀유지, 손해배상, 계약의 해제·해지, 불가항력, 권리·의무의 양도 금지, 통지, 분쟁 해결(관할법원), 완전합의 및 계약의 변경, 계약의 해석. 일반적인 경우를 위한 예시 문장이니 계약에 맞게 고쳐 쓰세요.
searchCases에 검색 함수를 넘기면 오른쪽 패널에 판례 검색 칸이 생겨요. 결과를 누르면 커서 위치에 대법원 2016. 4. 28. 선고 2015다12345 판결 같은 인용 문구가 들어가고, 인용 링크도 자동으로 붙어요.
<LegalEditor searchCases={async (q) => (await fetch(`/api/cases?q=${encodeURIComponent(q)}`)).json()} />
라이브러리는 검색을 직접 부르지 않아요. 국가법령정보 공동활용 API는 발급받은 인증값이 필요해서 서버를 거쳐야 하거든요. 연결 예제는 examples/law-go-kr-proxy에 있어요.
<LegalEditor autoFees />로 켜면, 입력값 소가(또는 소송목적의 값)를 넣었을 때 이름이 인지액·송달료로 시작하는 변수(예: {{인지액 산정 필요}})를 계산해서 채워요. 직접 입력한 값이 있으면 그 값을 써요.
첨부서류의 {{입증방법 통수}}·{{소장 부본 통수}}는 소가가 없어도 상대방 수로 채워요(피고 1명이면 위 입증방법 각 2통, 소장 부본 1통).
지급명령 신청서(payment-order 템플릿)는 청구금액을 넣으면 {{독촉절차 인지대}}·{{독촉절차 송달료}}·{{독촉절차비용}}(두 금액 합계)을 채워요.
| 항목 | 기준 | 근거 |
|---|---|---|
| 인지액 | 1천만원 미만 × 0.5% / 1억원 미만 × 0.45% + 5천원 / 10억원 미만 × 0.4% + 5만5천원 / 그 이상 × 0.35% + 55만5천원. 100원 미만 버림, 최저 1천원 | 「민사소송 등 인지법」 제2조 |
| 전자소송 인지액 | 위 계산식 × 0.9 후 100원 미만 버림, 최저 900원 — autoFees={{ electronic: true }} | 인지법 제16조, 전자소송포털 |
| 송달료 | 당사자 수 × 회분 × 1회 송달료. 소가 3천만원 이하(소액) 10회분, 넘으면 15회분. 당사자 수 기본 2 — autoFees={{ parties: 3 }} | 「송달료규칙의 시행에 따른 업무처리요령」 별표 1, 「소액사건심판규칙」 제1조의2 |
| 지급명령 인지대 | 소장 인지액 계산식 × 1/10 후 같은 끝자리 처리 (예: 청구금액 300만원 → 1,500원). 전자신청 감액은 아직 반영하지 않음 | 인지법 제7조제2항·제4항 |
| 지급명령 송달료 | 당사자 수 × 6회분 × 1회 송달료 | 업무처리요령 별표 1 |
| 1회 송달료 | 5,500원 (2025. 6. 1.부터). 바뀌면 autoFees={{ unitFee: 5600 }}처럼 덮어쓰기 | 법원 공지 |
| 첨부서류 서증 사본 통수 | {{입증방법 통수}} = 상대방 수 + 1. 상대방 수 기본은 당사자 수 − 1 — autoFees={{ opponents: 2 }}. 전자소송(electronic)은 채우지 않음 | 「민사소송규칙」 제105조제2항 |
| 소장·답변서·준비서면 부본 통수 | {{소장 부본 통수}}·{{답변서 부본 통수}}·{{준비서면 부본 통수}} = 상대방 수 | 「민사소송규칙」 제48조제1항, 「민사소송법」 제256조제3항(답변서 부본은 원고에게 송달)·제273조(준비서면 부본은 상대방에게 송달), 대한법률구조공단 첨부서류 작성방법 |
계산 결과는 참고용이에요. 제1심 소장 기준이고 항소·상고·반소는 계산하지 않아요. 실제 납부액은 법원 안내를 확인하세요.
전자소송(
autoFees={{ electronic: true }})에서는 첨부서류 통수를 채우지 않아요. 전자소송 동의를 한 상대방에게 보낼 부본·사본은 내지 않아도 되고(민사소송 등에서의 전자문서 이용 등에 관한 업무처리지침 제23조제3항), 그 밖의 상대방에게는 법원이 출력해 송달하기 때문이에요(「민사소송 등에서의 전자문서 이용 등에 관한 법률」 제12조제1항). 다만 출력할 분량이 50쪽 이상이거나 상대방이 5명 이상이면 법원이 출력서면 제출을 명할 수 있어요(같은 지침 제23조제1항).
본문에서 금액을 선택하고 도구 모음의 금액이나 더보기(⋯)의 금액을 한글로를 누르면 선택한 글의 숫자만 뽑아 바꿔요.
| 서식 | 예 |
|---|---|
| 소장식 | 금 37,200,000원 |
| 계약서식 | 금 삼천칠백이십만 원정(₩37,200,000) |
한글 금액은 만 단위로 끊고, 고쳐 쓰기 어렵도록 "일"을 빼지 않고 적어요 (10,000 → 일만, 11 → 일십일, 410,000,000 → 사억일천만).
| 이름 | 설명 |
|---|---|
<LegalEditor content values onChange onValuesChange editable autoFees searchCases clauses templates hwpWasmUrl /> | 에디터 컴포넌트 |
clauses | 기본 조항 목록 { id, title, category, html }[] |
groupClauses(clauses, { category, query }) | 조항·템플릿을 분류별로 묶음 [분류, 항목[]][] (분류 선택·검색 적용) — groupClauses(templates) |
formatCaseCitation(result) | 판례 검색 결과 → 대법원 2016. 4. 28. 선고 2015다12345 판결 |
calcStampFee(소가, { electronic }) | 소장 인지액(원) |
calcPaymentOrderStampFee(청구금액) | 지급명령 신청서 인지대(원) — 종이 신청 기준 |
calcServiceFee({ parties, procedure, unitFee }) | 송달료(원). procedure: 소액·단독·합의·항소·상고·조정·독촉 |
withCourtFees(names, values, options) | 비어 있는 인지액…·송달료… 변수를 계산값으로 채운 입력값 |
templates | 기본 문서 템플릿 { id, title, category, description, html }[] (분류 순서: 원고·신청인 → 피고 → 기타) — <LegalEditor content={templates[0].html} /> |
toKoreanAmount(n) | 37200000 → 삼천칠백이십만 |
formatAmount(n, '소장' | '계약서') | 금 37,200,000원 / 금 삼천칠백이십만 원정(₩37,200,000) |
parseAmount(text) | 글에서 숫자만 뽑기 (금 37,200,000원 → 37200000) |
fillTemplate(html, values) | 변수를 채운 완성본 HTML. .legal-doc 안에서 렌더하면 번호가 붙어요 |
toDocx(editor.getJSON(), values) | .docx Blob 생성 |
toHwpx(editor.getJSON(), values) | .hwpx Blob 생성 |
toHwp(editor.getJSON(), values, { wasm }) | .hwp(HWP 5.0) Blob 생성. wasm은 WASM 주소나 바이트(선택) |
toPlainHtml(editor.getJSON(), values) | 번호가 텍스트로 들어간 독립 HTML |
.hwp 바이너리로 바로 저장 (rhwp).doc 열기 (@file-viewer/doc)저장소에 사이트 배포 설정이 들어 있어요. 데모 페이지(index.html)를 앱으로 빌드하고, 판례 검색은 Vercel 함수(api/cases.js)가 국가법령정보 공동활용 API를 불러요.
vercel.json이 정해요 — vite build --config vite.site.config.ts → site/LAW_GO_KR_OC(국가법령정보 공동활용 인증값)를 넣고 다시 배포하세요. 없으면 판례 검색만 "아직 설정되지 않았어요"로 나오고 나머지 기능은 그대로 돼요.main에 올라갈 때마다 자동으로 다시 배포돼요.npx vite build --config vite.site.config.ts && npx vite preview --config vite.site.config.ts (이때는 판례 검색 함수가 돌지 않아요)npm i
npm run dev # 데모: http://localhost:5173
npm run build # dist/
MIT
fromFile(file).docx / .doc / .hwp / .hwpx를 에디터용 HTML로 변환 (fromDocx, fromDoc, fromHwp도 있음) |
normalizeLegalHtml(html) | "제N조 / ① / 1. / 갑 제N호증" 문단을 조·항·호·호증 구조로 변환 |
Variable | 다른 Tiptap 에디터에 넣어 쓸 수 있는 변수 확장 |
Numbering | 번호·호증 문단 확장 (setNumbering(1~4 | null), setEvidence('갑' | '을' | '병' | null), setEvidenceStart(n | null), Tab·Shift+Tab 단계 변경, 맨 앞 Backspace 해제) |
EvidenceRef | 본문 호증 참조 확장 (LegalEditor에는 이미 들어 있음). evidenceLabels(editor.getJSON())로 호증 id별 현재 번호 |
findCitations(text) | 글에서 판례·법령 인용 찾기 → { type: 'case' | 'law', text, from, to, url }[] |
CitationLink | 인용에 밑줄·링크를 덧입히는 확장 (LegalEditor에는 이미 들어 있음) |