diff --git a/.loki/reference/chrome_laptop_toast_ToastHavingDetailModal_Default.png b/.loki/reference/chrome_laptop_toast_ToastHavingDetailModal_Default.png
new file mode 100644
index 00000000..361e5672
Binary files /dev/null and b/.loki/reference/chrome_laptop_toast_ToastHavingDetailModal_Default.png differ
diff --git a/.loki/reference/chrome_laptop_toast_Toast_Default.png b/.loki/reference/chrome_laptop_toast_Toast_Default.png
new file mode 100644
index 00000000..361e5672
Binary files /dev/null and b/.loki/reference/chrome_laptop_toast_Toast_Default.png differ
diff --git a/src/components/toast/Toast.stories.tsx b/src/components/toast/Toast.stories.tsx
new file mode 100644
index 00000000..c6147d28
--- /dev/null
+++ b/src/components/toast/Toast.stories.tsx
@@ -0,0 +1,18 @@
+import React from "react";
+import { toast } from "react-toastify";
+import { Toast } from "./Toast";
+import { Toaster } from "./Toaster";
+
+export default {
+ component: Toast,
+ title: "toast/Toast",
+};
+
+export const Default = (): JSX.Element => {
+ return (
+
+
+
+
+ );
+};
diff --git a/src/components/toast/Toast.test.tsx b/src/components/toast/Toast.test.tsx
new file mode 100644
index 00000000..95affea6
--- /dev/null
+++ b/src/components/toast/Toast.test.tsx
@@ -0,0 +1,14 @@
+import "@testing-library/jest-dom/extend-expect";
+import { screen } from "@testing-library/react";
+import React from "react";
+import { render } from "../../test-utils";
+import { Default } from "./Toast.stories";
+
+describe("Toast", () => {
+ test("should toast alert", async () => {
+ render();
+ expect(screen.queryAllByRole("alert")).toHaveLength(0);
+ screen.getByRole("button").click();
+ await expect(screen.findAllByRole("alert")).resolves.toBeDefined();
+ });
+});
diff --git a/src/components/toast/Toast.tsx b/src/components/toast/Toast.tsx
new file mode 100644
index 00000000..f9060f8a
--- /dev/null
+++ b/src/components/toast/Toast.tsx
@@ -0,0 +1,13 @@
+import Alert, { AlertProps } from "@mui/material/Alert";
+import React from "react";
+
+export type ToastProps = AlertProps;
+export const Toast = ({ sx, ...delegated }: ToastProps): JSX.Element => {
+ return (
+
+ );
+};
diff --git a/src/components/toast/ToastHavingDetailInfo.stories.tsx b/src/components/toast/ToastHavingDetailInfo.stories.tsx
new file mode 100644
index 00000000..0ad55e1f
--- /dev/null
+++ b/src/components/toast/ToastHavingDetailInfo.stories.tsx
@@ -0,0 +1,36 @@
+import React from "react";
+import { toast } from "react-toastify";
+import { ErrorMessage } from "../ErrorMessage";
+import { ToastHavingDetailModal } from "./ToastHavingDetailInfo";
+import { Toaster } from "./Toaster";
+
+export default {
+ component: ToastHavingDetailModal,
+ title: "toast/ToastHavingDetailModal",
+};
+
+export const Default = (): JSX.Element => {
+ return (
+
+
+
+
+ );
+};
diff --git a/src/components/toast/ToastHavingDetailInfo.test.tsx b/src/components/toast/ToastHavingDetailInfo.test.tsx
new file mode 100644
index 00000000..f3675ab8
--- /dev/null
+++ b/src/components/toast/ToastHavingDetailInfo.test.tsx
@@ -0,0 +1,19 @@
+import "@testing-library/jest-dom/extend-expect";
+import { getByRole } from "@testing-library/dom";
+import { screen } from "@testing-library/react";
+import React from "react";
+import { render } from "../../test-utils";
+import { Default } from "./ToastHavingDetailInfo.stories";
+
+describe("Toast", () => {
+ test("should toast alert having button that display alert dialog", async () => {
+ render();
+ expect(screen.queryAllByRole("alert")).toHaveLength(0);
+ screen.getByRole("button").click();
+ await expect(screen.findAllByRole("alert")).resolves.toBeDefined();
+
+ const toast = screen.getAllByRole("alert")[0];
+ getByRole(toast, "button").click();
+ expect(screen.getByRole("alertdialog")).toBeDefined();
+ });
+});
diff --git a/src/components/toast/ToastHavingDetailInfo.tsx b/src/components/toast/ToastHavingDetailInfo.tsx
new file mode 100644
index 00000000..f6062600
--- /dev/null
+++ b/src/components/toast/ToastHavingDetailInfo.tsx
@@ -0,0 +1,44 @@
+import Button, { ButtonProps } from "@mui/material/Button";
+import Dialog from "@mui/material/Dialog";
+import React, { useState, ReactNode } from "react";
+import { DialogCloseButton } from "../dialog/DialogCloseButton";
+import { DialogWrapper } from "../dialog/DialogWrapper";
+import { Toast, ToastProps } from "./Toast";
+
+export type ToastHavingDetailModalProps = {
+ detailContent: ReactNode;
+ detailButtonProps?: Omit;
+} & Omit;
+export const ToastHavingDetailModal = ({
+ detailContent,
+ detailButtonProps,
+ ...delegated
+}: ToastHavingDetailModalProps): JSX.Element => {
+ const [open, setOpen] = useState(false);
+ return (
+ <>
+ {
+ e.stopPropagation();
+ setOpen(true);
+ }}
+ color="inherit"
+ variant="text"
+ {...detailButtonProps}
+ >
+ {detailButtonProps?.children ?? "Detail"}
+
+ }
+ />
+
+ >
+ );
+};
diff --git a/src/components/toast/Toaster.tsx b/src/components/toast/Toaster.tsx
new file mode 100644
index 00000000..9edf856b
--- /dev/null
+++ b/src/components/toast/Toaster.tsx
@@ -0,0 +1,27 @@
+import { useTheme } from "@mui/material/styles";
+import React from "react";
+import { ToastContainer, ToastContainerProps } from "react-toastify";
+import "react-toastify/dist/ReactToastify.css";
+
+export type ToasterProps = ToastContainerProps;
+export const Toaster = ({
+ position,
+ theme,
+ progressStyle,
+ limit,
+ ...delegated
+}: ToasterProps): JSX.Element => {
+ const muiTheme = useTheme();
+ return (
+
+ );
+};