커스텀 템플릿 vs. 커스텀 코드 블록
- 커스텀 템플릿은 기존 블록의 렌더링을 직접 만든 마크업으로 대체하고, 해당 블록의 자체 데이터(Header의 제목과 아이템 수, Summary의 총액 등)를 전달해요. 새로운 것을 추가하지 않고 블록 하나의 스타일을 바꿔요.
- Custom code 블록은 장바구니 어디에나 임의의 HTML 또는 React로 된 새 블록을 추가해요.
커스텀 템플릿 사용하기
- 에디터에서 블록을 선택하고 Code 탭을 여세요.
- 기본 템플릿을 편집하세요. 커스텀 템플릿은 JSX 전용이에요(HTML/JSX 선택은 Custom code 블록에만 있어요).
- Compile을 클릭하세요. 컴파일은 타입을 제거하고 JSX를 트랜스파일하므로 구문(syntax) 오류를 잡아내요. 타입 오류는 컴파일을 막지 않아요 — 에디터가 입력하는 동안 인라인으로 표시하며, 블록의 props를 자동 완성하는 것과 같은 IntelliSense를 사용해요.
- 템플릿을 켜서 장바구니가 기본 렌더링 대신 이를 사용하도록 하세요.
- Reset to default는 언제든지 블록의 원래 템플릿을 복원해요.
AI로 템플릿 작성하기
- 컴파일 규칙(단일 표현식,
export default없음, import 없음) - 에디터의 IntelliSense가 표시하는 것과 일치하는, 블록이 받는 정확한 props
- 에디터가 강제하는 잠긴 함수 시그니처
- 블록별 규칙(금액 형식, 연결해야 할 핸들러, 접근성 요구 사항)
- 현재 템플릿을 붙여넣고 원하는 변경 사항을 설명하는 작성란
프롬프트는 각 블록에 특화되어 있어요. Copy AI prompt 버튼은 커스텀 템플릿을 지원하는 블록에만 표시돼요.
템플릿이 대체하는 것
유지되는 것: 장바구니 내 블록의 위치, 표시 여부 토글, 설정(여전히 받는 props에 반영됨), 장바구니의 커스텀 CSS 패널, 그리고 기본 로딩 스켈레톤이에요.
마지막 항목이 사람들을 놀라게 해요. 블록은 템플릿에 도달하기 전에 장바구니가 아직 로딩 중인지 확인하므로, 로드 중에는 기본 스켈레톤이 렌더링되고 장바구니가 준비된 후에만 템플릿이 실행돼요. 로딩 상태를 직접 만들 필요가 없어요.
템플릿 안에서 사용 가능한 것
- 다섯 가지 훅을 사용할 수 있어요:
useState,useEffect,useMemo,useRef,useCallback. 그리고<>…</>를 위한Fragment도 있어요. - import는 없어요. 아무것도
import할 수 없고, 스코프에React객체가 없으므로React.useReducer,React.Children도 없어요. 위 목록에 없는 훅은 사용할 수 없어요. - props는 읽기 전용이에요. prop을 변경해도 유용한 결과가 없어요. 장바구니를 변경하려면 props에 직접 쓰지 말고 블록이 제공하는 핸들러 props(
onClose,increment,selectPlan등)를 사용하세요. window에 접근할 수 있으므로, 블록의 props가 다루지 않는 것이 필요할 때 템플릿에서window.aftersell.cart를 통해 Cart SDK를 호출할 수 있어요.
모든 블록에 공통되는 규칙
*Htmlprops는 미리 정제된 리치 텍스트예요.dangerouslySetInnerHTML로 렌더링하세요. 이미 장바구니의 정제기(sanitizer)를 거쳤고,{{total_price}}같은 머천트 토큰은 이미 치환되어 있어요.string으로 도착하는 가격은 이미 스토어 통화 형식으로 포맷되어 있어요.number가격은 센트 단위예요. 블록은 둘 중 하나를 제공하며, 각 블록의 표에 어느 것인지 나와 있어요.- 템플릿 안에서
isLoading은 항상false예요. 블록은 기본 스켈레톤을 렌더링하고 장바구니가 로드된 후에만 템플릿을 호출하므로, 이 prop은 분기용이 아니라 완결성을 위해 전달돼요.
일부 블록은 특정 상태에서 아무것도 반환하지 않으므로, 템플릿이 빈 데이터로 호출되는 일이 없어요. Rewards 템플릿은 빈
milestones를 절대 보지 않고, Subscription upgrade 템플릿은 null인 view를 절대 보지 않아요. 각 블록의 레퍼런스에 해당 여부가 명시되어 있으므로 빈 상태 분기를 생략할 수 있어요.커스텀 템플릿 스타일링
두 가지 클래스 패밀리
즉
cart-internal-header__title은 제목을 기본 제목처럼 보이게 만드는 것이고, cart-external-header__title은 모양을 바꾸고 싶을 때 잡아야 하는 손잡이예요.
작은 변경: 두 클래스명 모두 유지
cart-external-* 연결 지점을 대상으로 하는 커스텀 CSS로 스타일을 변경하세요.
구조 변경: 두 클래스명 모두 제거
cart-internal-*을 제거하세요. 구조가 바뀐 마크업에 그 클래스를 유지하면, 더 이상 존재하지 않는 요소를 가정하는 레이아웃 규칙을 상속해요: 다른 자식을 기대하는 flex 컨테이너, 이동한 요소 사이의 간격, 제거한 것을 기준으로 한 위치 지정 등이에요. 보통 기본 규칙이 이기고 있는데 여러분의 CSS가 “작동하지 않는” 것으로 나타나요.
만든 것에 스타일을 지정하는 두 가지 방법:
방법 1: 직접 만든 클래스명 + 커스텀 CSS
.header나 .title 같은 클래스가 장바구니 자체의 클래스, 다른 앱의 템플릿, 또는 미래의 블록과 충돌할 위험이 있어요.
방법 2: 인라인 스타일
:hover 같은 의사 클래스가 없고, 미디어 쿼리가 없고, 블록 간 재사용이 안 돼요. 이 중 하나라도 필요해지면 방법 1을 사용하세요.
접근 방식 선택하기
장바구니는 shadow root 안에 렌더링되므로 테마의 스타일시트가 안에 접근할 수 없어요. 커스텀 템플릿의 스타일은 테마가 아니라 장바구니 자체의 Custom CSS 패널이나 인라인 스타일에서 와야 해요. 커스텀 CSS를 참고하세요.
템플릿이 실패할 때
블록이 눈에 보이는 오류 없이 조용히 사라지므로, 게시하기 전에 항상 미리보기에서 템플릿을 확인하세요. 블록이 사라졌다면 먼저 브라우저 콘솔을 여세요.
주의해야 할 두 가지가 있어요. 둘 다 그렇지 않다고 가정하는 템플릿을 크래시시키니까요:
- null이 될 수 있는 props. 많은 props가 정상 상황에서
null이에요(로고가 없을 때logoUrl, 이미지가 없을 때imageUrl, 단일 옵션 상품의variantTitle). 사용하기 전에 확인하세요. - 비어 있을 수 있는 배열.
discountTags와discountCodes는 비어 있는[]인 경우가 훨씬 많아요.
제한 사항
- 커스텀 템플릿은 표시 재정의예요. 장바구니에 대한 로직 실행(이벤트 구독, 아이템 추가, 변경에 반응)은 커스텀 스크립트와 Cart SDK를 사용하세요.
- 거의 모든 블록이 지원해요. 예외는 Shopify 자체 결제 버튼을 담는 Express payments 블록과 Cart items 컨테이너 자체예요. 다만 그 안의 Product 행은 커스텀 템플릿을 지원해요.
- 템플릿은 블록의 근본적인 동작을 바꿀 수 없어요. 블록 데이터의 표시 방식을 바꾸는 것이지, 그 뒤의 데이터나 동작을 바꾸는 것이 아니에요.
각 블록의 props
Custom code 블록은 블록의 렌더링을 대체하는 것이 아니라 마크업을 추가하는 유일한 영역이므로 props가 달라요: 전체 장바구니와 장바구니 추가 액션이에요. 커스텀 코드 블록 → Props를 참고하세요.