Goey Toast là một package React dành cho những giao diện muốn thông báo trạng thái theo cách trực quan hơn toast hình chữ nhật truyền thống. Thay vì chỉ trượt vào rồi biến mất, toast có thể co giãn, morph từ pill thành blob và phản hồi với thao tác hover, dismiss hoặc hoàn tất một promise.
Trong bài này, chúng ta sẽ tích hợp goey-toast vào một ứng dụng React từ đầu, kiểm tra API thực tế của repository anl331/goey-toast, đồng thời phân tích khi nào hiệu ứng gooey đáng dùng và khi nào nên ưu tiên một toast đơn giản hơn.
Câu trả lời ngắn: Goey Toast là component notification cho React, xây trên Sonner và Framer Motion. Bạn cần import stylesheet của package một lần, mountGooeyToastervà gọi các hàm nhưgooeyToast.success(),gooeyToast.promise()hoặcgooeyToast.dismiss().
Goey Toast là gì?
Goey Toast là package mã nguồn mở có giấy phép MIT, phát hành dưới tên goey-toast. Snapshot repository được kiểm tra trong bài này là phiên bản 0.5.0. Package sử dụng Sonner làm nền tảng quản lý toast và Framer Motion để xử lý animation. Vì vậy, đây không phải plugin WordPress hay extension cho Ghost; nó phù hợp với ứng dụng React hoặc frontend có pipeline JavaScript hiện đại.
Điểm khác biệt nằm ở chuyển động morphing: toast có thể bắt đầu ở dạng pill, mở rộng thành vùng nội dung có description/action rồi co lại khi đóng. README của dự án cũng cung cấp các preset như smooth, bouncy, subtle và snappy để cân bằng giữa cảm giác mềm mại và tốc độ phản hồi.
Yêu cầu trước khi cài
Repository yêu cầu Node.js từ 18 trở lên và React/React DOM từ 18. Ngoài package chính, ứng dụng cần có Framer Motion. Sonner là dependency runtime của package, còn stylesheet của Goey Toast phải được import rõ ràng trong entry point.
node --version
npm install goey-toast
npm install react react-dom framer-motionNếu dự án dùng pnpm hoặc yarn, có thể thay lệnh cài tương ứng. Điều quan trọng là kiểm tra lockfile sau khi cài và tránh cài thêm một bản React thứ hai trong monorepo, vì hai React instance có thể gây lỗi hook hoặc context.
Import stylesheet và mount GooeyToaster
Bước dễ bị bỏ quên nhất là import CSS. Nếu chỉ import component mà bỏ stylesheet, toast có thể xuất hiện nhưng thiếu layout, màu nền hoặc animation đúng như demo.
import { GooeyToaster, gooeyToast } from 'goey-toast'
import 'goey-toast/styles.css'
export default function App() {
return (
<>
<main>
<h1>Dashboard</h1>
<button onClick={() => gooeyToast.success('Đã lưu thay đổi')}>
Lưu cấu hình
</button>
</main>
<GooeyToaster position="bottom-right" />
</>
)
}Nên mount một GooeyToaster ở cấp layout hoặc root app thay vì tạo một toaster trong từng component. Cách này giúp mọi module gọi API toast thống nhất, giảm nguy cơ có nhiều queue và giúp kiểm soát theme, offset, khoảng cách, close button hoặc giới hạn queue từ một nơi.
Các loại toast cơ bản
API chính cung cấp toast trung tính qua gooeyToast() và các biến thể ngữ nghĩa gồm success, error, warning và info. Hãy chọn loại theo ý nghĩa của sự kiện thay vì chỉ chọn theo màu sắc.
gooeyToast('Đang đồng bộ dữ liệu')
gooeyToast.success('Lưu thành công')
gooeyToast.error('Không thể kết nối máy chủ')
gooeyToast.warning('Phiên đăng nhập sắp hết hạn')
gooeyToast.info('Bạn có bản cập nhật mới')Thông báo lỗi nên nói rõ người dùng cần làm gì tiếp theo. Một câu “Error” không hữu ích bằng “Không thể tải danh sách; kiểm tra kết nối rồi thử lại”.
Toast có description và action
Với các sự kiện cần giải thích hoặc cho phép khôi phục, truyền thêm description và action. Description có thể là string hoặc React component, vì vậy bạn có thể đưa link hoặc nội dung định dạng mà vẫn giữ layout của toast.
gooeyToast.error('Upload thất bại', {
description: 'File vượt quá giới hạn 10 MB.',
action: {
label: 'Thử lại',
onClick: () => retryUpload(),
successLabel: 'Đã thử lại',
},
duration: 7000,
})Action không nên biến toast thành một dialog thu nhỏ. Chỉ đưa vào đó một hành động ngắn, có thể thực hiện ngay và không cần nhiều trường nhập liệu.
Promise toast cho request bất đồng bộ
Đây là API phù hợp với submit form, upload hoặc gọi endpoint. Goey Toast có thể biểu diễn ba trạng thái loading, success và error trên cùng một luồng promise, giúp người dùng thấy request đã bắt đầu và kết thúc thế nào.
async function saveSettings(payload: Settings) {
return gooeyToast.promise(api.saveSettings(payload), {
loading: 'Đang lưu cấu hình…',
success: 'Cấu hình đã được lưu',
error: 'Lưu thất bại, vui lòng thử lại',
})
}Không nên dùng promise toast cho một thao tác kéo dài hàng phút nếu ứng dụng không có tiến độ thật. Khi đó, một progress UI trong trang sẽ trung thực hơn thông báo tự đóng.
Cập nhật và dismiss toast theo ID
Khi cần cập nhật một thông báo đang hiển thị, truyền một id ổn định rồi dùng gooeyToast.update(). Dismiss có thể nhận ID, bộ lọc theo type hoặc đóng toàn bộ.
const id = 'sync-status'
gooeyToast.loading('Đang đồng bộ…', { id })
// Sau khi request hoàn tất
gooeyToast.update(id, {
type: 'success',
title: 'Đồng bộ xong',
description: 'Dữ liệu đã cập nhật lúc vừa rồi.',
})
gooeyToast.dismiss(id)Giữ ID ở một hằng số hoặc trong state của workflow thay vì sinh ID ngẫu nhiên ở nhiều nơi. Nếu không, update có thể không trúng toast đang hiển thị và người dùng thấy hai thông báo chồng lên nhau.
Tùy biến vị trí, theme và animation
GooeyToaster hỗ trợ nhiều vị trí, theme, offset, gap, preset, spring và bounce. Với website nội dung, bottom-right thường ít che nội dung chính hơn. Với ứng dụng có thanh điều hướng cố định, cần đo offset thực tế thay vì để toast đè lên nút hành động.
<GooeyToaster
position="top-right"
theme="dark"
preset="smooth"
closeOnEscape
closeButton
showProgress
maxQueue={4}
queueOverflow="drop-oldest"
/>Hiệu ứng bouncy tạo cảm giác vui nhưng có thể không phù hợp với thao tác lỗi liên tục hoặc dashboard nghiêm túc. Hãy ưu tiên preset ít gây xao nhãng nếu toast xuất hiện thường xuyên.
Accessibility và mobile
Animation không thay thế được nội dung rõ ràng. Toast cần có title có nghĩa, tương phản màu đủ, thời gian hiển thị phù hợp và hành vi dismiss bằng bàn phím. Bật closeOnEscape nếu toast có nội dung dài hoặc action. Khi dùng trên mobile, kiểm tra swipe-to-dismiss, vùng chạm và khoảng cách với safe area.
Đừng chỉ dùng màu xanh cho success hoặc màu đỏ cho error; nội dung và biểu tượng cũng phải truyền tải trạng thái. Nếu người dùng cần nhiều thời gian để đọc, tăng duration hoặc cung cấp một nơi xem lại thông báo thay vì ép họ đọc trong vài giây.
Trade-off khi đưa vào production
Goey Toast phù hợp khi trải nghiệm chuyển động là một phần của ngôn ngữ sản phẩm. Tuy nhiên, Framer Motion và animation phức tạp có thể làm tăng chi phí bundle, thời gian render hoặc cảm giác nặng trên thiết bị yếu. Trước khi dùng rộng rãi, hãy đo bundle production, kiểm tra reduced-motion và thử với hàng chục toast liên tiếp.
Với một blog hoặc trang quản trị đơn giản, Sonner thuần hoặc một component CSS nhỏ có thể đủ dùng. Goey Toast đáng cân nhắc khi sản phẩm cần visual identity riêng, có nhiều workflow bất đồng bộ và đội frontend chấp nhận bảo trì một lớp animation bổ sung.
Checklist tích hợp
- Kiểm tra Node.js, React và peer dependencies.
- Import
goey-toast/styles.cssmột lần ở entry point. - Mount một
GooeyToasterở root layout. - Dùng semantic type và nội dung lỗi có hướng dẫn.
- Dùng
promisecho request ngắn, có trạng thái kết thúc rõ. - Test keyboard, Escape, mobile swipe, dark mode, RTL và reduced-motion.
- Đo bundle và kiểm tra queue trước khi bật trên toàn bộ ứng dụng.
Kết luận
Goey Toast là một lựa chọn thú vị cho React nếu bạn muốn toast notification có chuyển động morphing thay vì chỉ là một hộp thông báo. Cách tích hợp không phức tạp: cài package, import CSS, mount toaster và gọi API phù hợp. Phần khó hơn là chọn đúng nơi để dùng animation, viết thông báo dễ hiểu và bảo đảm accessibility.
Để đặt bài này trong hệ sinh thái TechNT, bạn có thể đọc thêm bài cấu hình Nginx reverse proxy cho nhiều website khi triển khai frontend React lên VPS. Nguồn chính thức gồm repository goey-toast, demo/docs và package metadata snapshot 0.5.0.