문서
SDUI
Server-Driven UI로 동적 인터페이스를 구축하세요.
개요
Server-Driven UI를 사용하면 JSON으로 UI 구조를 정의하고 동적으로 렌더링할 수 있습니다.
SDUI (Server-Driven UI)는 서버가 JSON으로 UI 정의를 전송하고 클라이언트가 컴포넌트 레지스트리를 사용하여 렌더링하는 패턴입니다. 이를 통해:
- 앱 릴리스 없이 동적 UI 업데이트
- 서버에서 다른 레이아웃의 A/B 테스트
- 사용자 데이터 기반 개인화된 경험
- JSON 정의로 빠른 프로토타이핑
Import
import {
defaultRegistry,
extendRegistry,
type SDUINode,
type SDUIPageSchema
} from '@hua-labs/ui/sdui';Hue 에디터
코드 작성 없이 드래그앤드롭으로 SDUI 인터페이스를 만들 수 있는 비주얼 에디터입니다.
Hue - 비주얼 SDUI 에디터
Hue는 누구나 SDUI를 쉽게 사용할 수 있도록 개발 중인 비주얼 에디터입니다. UI를 시각적으로 디자인하고 프로덕션 레디 JSON으로 내보내세요.
기능
- 드래그앤드롭 UI 구성 - 팔레트에서 컴포넌트를 드래그하여 레이아웃 구성
- 실시간 프리뷰 - 디자인하면서 변경 사항을 즉시 확인
- 속성 편집 패널 - 직관적인 컨트롤로 컴포넌트 props 설정
- SDUI JSON 내보내기 - 디자인을 프로덕션 레디 JSON 스키마로 내보내기
- 조건부 렌더링 및 액션 시스템 - 코드 작성 없이 인터랙티브 기능 추가
Hue는 현재 개발 중입니다. GitHub에서 업데이트를 확인하세요!
스키마 구조
SDUI JSON 스키마 형식 이해하기.
SDUINode
SDUI의 기본 빌딩 블록. 각 노드는 props와 children을 가진 컴포넌트를 나타내요.
TypeScripttypescript
interface SDUINode {
type: string; // Component type (e.g., "Button", "Card")
props?: Record<string, unknown>; // Component props
children?: SDUINode[] | string; // Child nodes or text content
key?: string; // Unique key for lists
when?: SDUICondition; // Conditional rendering
on?: SDUIEventHandlers; // Event handlers
}SDUIPageSchema
메타데이터와 루트 노드를 포함한 전체 페이지 정의.
TypeScripttypescript
interface SDUIPageSchema {
id: string; // Page ID
title?: string; // Page title
meta?: {
description?: string;
keywords?: string[];
};
data?: Record<string, unknown>; // Initial data context
root: SDUINode; // Root component tree
}컴포넌트 레지스트리
사용 가능한 컴포넌트 및 레지스트리 확장 방법.
내장 컴포넌트
BoxFlexGridContainerSectionSpacerDividerTextH1H2H3H4LinkButtonBadgeAvatarSkeletonProgressInputTextareaLabelCheckboxSwitchCardCardHeaderCardTitleCardContentCardFooterAlertAccordionTabsHeroSectionHeaderImageIcon레지스트리 확장하기
custom-registry.tstypescript
import { defaultRegistry, extendRegistry } from '@hua-labs/ui/sdui';
const customRegistry = extendRegistry({
// Add your custom components
MyCustomCard: ({ title, children }) => (
<div className="custom-card">
<h3>{title}</h3>
{children}
</div>
),
// Override existing components
Button: ({ variant = 'custom', ...props }) => (
<button className={`btn-${variant}`} {...props} />
),
});
export { customRegistry };이벤트 및 액션
이벤트 핸들러와 액션으로 유저 인터랙션 처리.
조건부 렌더링
when 속성으로 컴포넌트를 조건부로 렌더링해요.
JSON
{
"type": "Button",
"props": { "children": "Login" },
"when": {
"path": "user.isLoggedIn",
"operator": "eq",
"value": false
}
}지원되는 연산자
| Operator | Description |
|---|---|
| eq | 같음 |
| neq | 같지 않음 |
| gt / lt | 보다 큼 / 보다 작음 |
| exists | 값이 존재함 |
| notExists | 값이 존재하지 않음 |
이벤트 핸들러
JSON
{
"type": "Button",
"props": { "children": "Submit" },
"on": {
"click": {
"type": "api",
"payload": {
"method": "POST",
"endpoint": "/api/submit"
}
}
}
}액션 타입
navigate- 페이지 이동api- API 호출setState- 상태 업데이트openModal/closeModal- 모달 열기/닫기custom- 커스텀 액션 핸들러
전체 예시
여러 컴포넌트가 포함된 전체 페이지 스키마.
landing-page.json
{
"id": "landing",
"title": "Welcome",
"root": {
"type": "Box",
"props": { "className": "min-h-screen" },
"children": [
{
"type": "Header",
"props": { "sticky": true, "blur": true },
"children": [
{
"type": "Flex",
"props": { "justify": "between", "align": "center" },
"children": [
{ "type": "H4", "children": "My App" },
{
"type": "Button",
"props": { "variant": "outline" },
"children": "Login",
"on": {
"click": {
"type": "navigate",
"payload": { "path": "/login" }
}
}
}
]
}
]
},
{
"type": "HeroSection",
"props": {
"title": "Welcome to My App",
"subtitle": "Built with SDUI",
"centered": true
}
}
]
}
}