Components

Toast

버튼으로 트리거되는 Toast 메시지를 나타내는 메뉴입니다.

    () => {
    const [open, setOpen] = React.useState(false)
    const eventDateRef = React.useRef(new Date())
    const timerRef = React.useRef(0)
    React.useEffect(() => {
    return () => clearTimeout(timerRef.current)
    }, [])
    return (
    <ToastProvider swipeDirection='right'>
    <Button onClick={() => { setOpen(false) window.clearTimeout(timerRef.current) timerRef.current = window.setTimeout(() => { setOpen(true) }, 100) }} >
    Add to calendar
    </Button>
    <Toast className='ToastRoot asd' open={open} onOpenChange={setOpen}>
    <ToastTitle className='ToastTitle'>Scheduled: Catch up</ToastTitle>
    <ToastDescription asChild>
    <div>
    2025-02-28 15:50:30
    </div>
    </ToastDescription>
    <ToastAction asChild altText='Goto schedule to undo' >
    <Button size={'1'} variant='soft'>
    Undo
    </Button>
    </ToastAction>
    </Toast>
    <ToastViewport className='ToastViewport' />
    </ToastProvider>
    )
    }

    API Reference

    Provider

    토스트와 토스트 뷰포트를 감싸는 요소입니다. 보통 애플리케이션을 포장합니다.

    PropTypeDefault
    duration
    number
    5000
    label*
    string
    "Notification"
    swipeDirection
    enum
    "right"
    swipeThreshold
    number
    50

    Viewport

    토스트가 나타나는 고정 영역입니다. 사용자는 핫키를 눌러 뷰포트로 이동할 수 있습니다. 키보드 사용자를 위해 핫키의 발견 가능성을 보장하는 것은 귀하에게 달려 있습니다.

    PropTypeDefault
    asChild
    boolean
    false
    hotkey
    string[]
    ["F8"]
    label
    string
    "Notifications ({hotkey})"

    Root

    자동으로 닫히는 토스트입니다. 사용자 응답을 얻기 위해 열어두어서는 안 됩니다.

    PropTypeDefault
    asChild
    boolean
    false
    type
    enum
    "foreground"
    duration
    number
    No default value
    defaultOpen
    boolean
    true
    open
    boolean
    No default value
    onOpenChange
    function
    No default value
    onEscapeKeyDown
    function
    No default value
    onPause
    function
    No default value
    onResume
    function
    No default value
    onSwipeStart
    function
    No default value
    onSwipeMove
    function
    No default value
    onSwipeEnd
    function
    No default value
    onSwipeCancel
    function
    No default value
    forceMount
    boolean
    No default value
    Data attributeValues
    [data-state]"open" | "closed"
    [data-swipe]"start" | "move" | "cancel" | "end"
    [data-swipe-direction]"up" | "down" | "left" | "right"
    CSS VariableDescription
    --radix-toast-swipe-move-x수평으로 스와이프할 때 토스트의 오프셋 위치입니다.
    --radix-toast-swipe-move-y수직으로 스와이프할 때 토스트의 오프셋 위치입니다.
    --radix-toast-swipe-end-x수평으로 스와이프한 후 토스트의 오프셋 끝 위치입니다.
    --radix-toast-swipe-end-y수직으로 스와이프한 후 토스트의 오프셋 끝 위치입니다.

    Title

    토스트의 선택적 제목입니다.

    PropTypeDefault
    asChild
    boolean
    false

    Description

    토스트 메시지입니다.

    PropTypeDefault
    asChild
    boolean
    false

    Action

    사용자가 예상치 못한 부작용 없이 작업을 완료할 수 있도록 보장하는 안전한 작업입니다. 사용자 응답이 필요한 경우, 토스트를 대화 상자로 포털하여 뷰포트에 스타일을 적용하세요.

    PropTypeDefault
    asChild
    boolean
    false
    altText*
    string
    No default value

    Close

    토스트가 지속 시간이 만료되기 전에 사용자가 토스트를 닫을 수 있도록 하는 버튼입니다.

    PropTypeDefault
    asChild
    boolean
    false

    Examples

    Custom hotkey

    기본 핫키를 재정의하여 각 키에 대한 event.code 값을 사용합니다.

    <Toast.Provider>
    {/* ... */}
    <Toast.Viewport hotkey={["altKey", "KeyT"]} />
    </Toast.Provider>

    Custom duration

    토스트의 지속 시간을 사용자 정의하여 제공자 값을 재정의합니다.

    <Toast.Root duration={3000}>
    <Toast.Description>저장되었습니다!</Toast.Description>
    </Toast.Root>

    Duplicate toasts

    사용자가 버튼을 클릭할 때마다 토스트가 나타나야 하는 경우, 상태를 사용하여 동일한 토스트의 여러 인스턴스를 렌더링합니다(아래 참조). 또는 부품을 추상화하여 고유한 명령형 API를 생성할 수 있습니다.

    export default () => {
    const [savedCount, setSavedCount] = React.useState(0);
    return (
    <div>
    <form onSubmit={() => setSavedCount((count) => count + 1)}>
    {/* ... */}
    <button>저장</button>
    </form>
    {Array.from({ length: savedCount }).map((_, index) => (
    <Toast.Root key={index}>
    <Toast.Description>저장되었습니다!</Toast.Description>
    </Toast.Root>
    ))}
    </div>
    );
    };

    Animating swipe gesture

    --radix-toast-swipe-move-[x|y]--radix-toast-swipe-end-[x|y] CSS 변수를 data-swipe="[start|move|cancel|end]" 속성과 결합하여 스와이프 닫기 제스처를 애니메이션화합니다. 예를 들어:

    // index.jsx
    import { Toast } from "@confy-ui/react/primitives";
    import "./styles.css";
    export default () => (
    <Toast.Provider swipeDirection="right">
    <Toast.Root className="ToastRoot">...</Toast.Root>
    <Toast.Viewport />
    </Toast.Provider>
    );
    /* styles.css */
    .ToastRoot[data-swipe="move"] {
    transform: translateX(var(--radix-toast-swipe-move-x));
    }
    .ToastRoot[data-swipe="cancel"] {
    transform: translateX(0);
    transition: transform 200ms ease-out;
    }
    .ToastRoot[data-swipe="end"] {
    animation: slideRight 100ms ease-out;
    }
    @keyframes slideRight {
    from {
    transform: translateX(var(--radix-toast-swipe-end-x));
    }
    to {
    transform: translateX(100%);
    }
    }

    Accessibility

    aria-live 요구 사항을 준수합니다.

    Sensitivity

    토스트의 민감도를 제어하기 위해 type prop을 사용하세요.

    사용자 작업의 결과로 생성된 토스트는 foreground를 선택하세요. 백그라운드 작업에서 생성된 토스트는 background를 사용해야 합니다.

    Foreground

    전경 토스트는 즉시 발표됩니다. 보조 기술은 전경 토스트가 나타날 때 이전에 대기 중인 메시지를 지울 수 있습니다. 동시에 서로 다른 전경 토스트를 쌓는 것을 피하세요.

    Background

    배경 토스트는 현재 문장을 읽는 것이 끝나는 다음 기회에 발표됩니다. 대기 중인 메시지를 지우지 않으므로, 사용자 상호작용에 대한 응답으로 과도하게 사용하는 경우 스크린 리더 사용자에게 지연된 사용자 경험으로 인식될 수 있습니다.

    <Toast.Root type="foreground">
    <Toast.Description>파일이 성공적으로 제거되었습니다.</Toast.Description>
    <Toast.Close>닫기</Toast.Close>
    </Toast.Root>
    <Toast.Root type="background">
    <Toast.Description>Confy-ui 1.0이 출시되었습니다.</Toast.Description>
    <Toast.Close>닫기</Toast.Close>
    </Toast.Root>

    Alternative action

    Action에서 altText prop을 사용하여 스크린 리더 사용자에게 토스트 작업을 수행하는 대체 방법을 안내합니다.

    사용자가 작업을 수행할 수 있는 애플리케이션의 영구적인 위치로 안내하거나, 고유한 핫키 논리를 구현할 수 있습니다. 후자를 구현하는 경우, 즉시 발표하기 위해 foreground 유형을 사용하고 사용자가 충분한 시간을 가질 수 있도록 지속 시간을 늘리세요.

    <Toast.Root type="background">
    <Toast.Title>업그레이드 가능!</Toast.Title>
    <Toast.Description>Confy-ui 1.0이 출시되었습니다.</Toast.Description>
    <Toast.Action altText="계정 설정으로 이동하여 업그레이드">
    업그레이드
    </Toast.Action>
    <Toast.Close>닫기</Toast.Close>
    </Toast.Root>
    <Toast.Root type="foreground" duration={10000}>
    <Toast.Description>파일이 성공적으로 제거되었습니다.</Toast.Description>
    <Toast.Action altText="실행 취소 (Alt+U)">
    실행 취소 <kbd>Alt</kbd>+<kbd>U</kbd>
    </Toast.Action>
    <Toast.Close>닫기</Toast.Close>
    </Toast.Root>

    Close icon button

    아이콘(또는 글꼴 아이콘)을 제공할 때, 스크린 리더 사용자를 위해 올바르게 레이블을 지정하는 것을 잊지 마세요.

    <Toast.Root type="foreground">
    <Toast.Description>저장되었습니다!</Toast.Description>
    <Toast.Close aria-label="닫기">
    <span aria-hidden>×</span>
    </Toast.Close>
    </Toast.Root>

    Keyboard Interactions

    KeyDescription
    F8
    토스트 뷰포트에 포커스를 이동합니다.
    Tab
    다음 포커스 가능한 요소로 포커스를 이동합니다.
    Shift + Tab
    이전 포커스 가능한 요소로 포커스를 이동합니다.
    Space
    Toast.Action 또는 Toast.Close에 포커스가 있을 때, 토스트를 닫습니다.
    Enter
    Toast.Action 또는 Toast.Close에 포커스가 있을 때, 토스트를 닫습니다.
    Esc
    Toast에 포커스가 있을 때, 토스트를 닫습니다.

    Custom APIs

    Abstract parts

    고유한 API를 생성하여 기본 부품을 추상화합니다.

    Usage

    import { Toast } from "./your-toast";
    export default () => (
    <Toast title="업그레이드 가능" content="Confy-ui 3.0이 출시되었습니다!">
    <button onClick={handleUpgrade}>업그레이드</button>
    </Toast>
    );

    Implementation

    // your-toast.jsx
    import { Toast as ToastPrimitive } from "@confy-ui/react/primitives";
    export const Toast = ({ title, content, children, ...props }) => {
    return (
    <ToastPrimitive.Root {...props}>
    {title && <ToastPrimitive.Title>{title}</ToastPrimitive.Title>}
    <ToastPrimitive.Description>{content}</ToastPrimitive.Description>
    {children && (
    <ToastPrimitive.Action asChild>{children}</ToastPrimitive.Action>
    )}
    <ToastPrimitive.Close aria-label="닫기">
    <span aria-hidden>×</span>
    </ToastPrimitive.Close>
    </ToastPrimitive.Root>
    );
    };

    Imperative API

    원하는 경우 토스트 중복을 허용하는 명령형 API를 생성합니다.

    Usage

    import { Toast } from "./your-toast";
    export default () => {
    const savedRef = React.useRef();
    return (
    <div>
    <form onSubmit={() => savedRef.current.publish()}>
    {/* ... */}
    <button>저장</button>
    </form>
    <Toast ref={savedRef}>성공적으로 저장되었습니다!</Toast>
    </div>
    );
    };

    Implementation

    // your-toast.jsx
    import * as React from "react";
    import { Toast as ToastPrimitive } from "@confy-ui/react/primitives";
    export const Toast = React.forwardRef((props, forwardedRef) => {
    const { children, ...toastProps } = props;
    const [count, setCount] = React.useState(0);
    React.useImperativeHandle(forwardedRef, () => ({
    publish: () => setCount((count) => count + 1),
    }));
    return (
    <>
    {Array.from({ length: count }).map((_, index) => (
    <ToastPrimitive.Root key={index} {...toastProps}>
    <ToastPrimitive.Description>{children}</ToastPrimitive.Description>
    <ToastPrimitive.Close>닫기</ToastPrimitive.Close>
    </ToastPrimitive.Root>
    ))}
    </>
    );
    });
    PreviousTab Nav