Guides

This section contains guides on how to use Solid Notifications.

Styling

Solid Notifications provides a flexible styling system that allows customization via CSS variables, dark mode support, toast types with predefined colors, and animations.

Copying the CSS file

The easiest way to get started with Solid Notifications is to copy the CSS file which can be found in the dist folder and edit it to suit your needs.

Customization via CSS Variables

You can customize the appearance of notifications using CSS variables. Below are the default variables used:

:root {
  /* General */
  --sn-z-index: 9999;
  --sn-color-default: #121826;
  --sn-color-success: #34ab53;
  --sn-color-error: #ea4335;
  --sn-color-warning: #f59e0b;
  --sn-color-info: #5493f7;

  /* Toast Wrapper */
  --sn-wrapper-max-width: 334px;
  --sn-wrapper-min-width: 264px;
  --sn-wrapper-transition-duration: 0.3s;

  /* Toast */
  --sn-toast-bg-color: white;
  --sn-toast-gap: 16px;
  --sn-toast-font-size: 0.875rem;
  --sn-toast-line-height: 1.5;
  --sn-toast-padding: 15px 16px 16px 16px;
  --sn-toast-text-color: #334155;
  --sn-toast-border-radius: 6px;
  --sn-toast-box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -2px,
    rgba(0, 0, 0, 0.3) 0px 3px 7px -3px;

  /* Dismiss Button */
  --sn-dismiss-btn-size: 1.175rem;
  --sn-dismiss-btn-border-radius: 0.25rem;
  --sn-dismiss-btn-transition: color 0.3s;
  --sn-dismiss-btn-margin: 1px -4px 0px auto;
  --sn-dismiss-btn-color: #9ca3af;
  --sn-dismiss-btn-hover-color: #374151;

  /* Progress Bar */
  --sn-progress-bar-height: 2px;
  --sn-progress-bar-color: #748aa8;

  /* Icon */
  --sn-icon-size: 1.125rem;
  --sn-icon-margin: 1px 0 0 0;
  --sn-icon-stroke: #fff;
  --sn-icon-fill: #121826;
}

/* Dark Theme */
.sn-theme-dark {
  --sn-toast-bg-color: #1f2937;
  --sn-toast-text-color: #f9fafb;
  --sn-toast-box-shadow: inset 0 0 0.5px 1px hsla(0, 0%, 100%, 0.075),
    0 0 0 1px hsla(0, 0%, 0%, 0.05), 0 0.3px 0.4px hsla(0, 0%, 0%, 0.02),
    0 0.9px 1.5px hsla(0, 0%, 0%, 0.045), 0 3.5px 6px hsla(0, 0%, 0%, 0.09);
  --sn-dismiss-btn-color: #bfc5cf;
  --sn-dismiss-btn-hover-color: #f9fafb;
  --sn-progress-bar-color: #9ca3af;
  --sn-icon-stroke: #fff;
}

/* Toast Types */
.sn-type-success {
  --sn-progress-bar-color: var(--sn-color-success);
  --sn-icon-fill: var(--sn-color-success);
}

.sn-type-error {
  --sn-progress-bar-color: var(--sn-color-error);
  --sn-icon-fill: var(--sn-color-error);
}

.sn-type-warning {
  --sn-progress-bar-color: var(--sn-color-warning);
  --sn-icon-fill: var(--sn-color-warning);
}

.sn-type-info {
  --sn-progress-bar-color: var(--sn-color-info);
  --sn-icon-fill: var(--sn-color-info);
}

You can override these values in your global CSS file or within a specific component.

Themes and Types

The toast tree consists of only three elements. A toaster, a toast wrapper, and a toast.

<div class="sn-toaster">
  <div class="sn-toast-wrapper">
    <div class="sn-toast">This is a notification</div>
  </div>
</div>

The way theming and types work in Solid Notifications is that the wrapper element will be provided with classes based on the provided settings. For example, if you set the theme to "dark", the wrapper will have the class "sn-theme-dark", and if you set the toast type to "success", the wrapper will have the class sn-type-success.

For example:

notify("This is a success notification", {
  theme: "dark",
  type: "success",
});

will result in the following HTML:

<div class="sn-toaster">
  <div class="sn-toast-wrapper sn-theme-dark sn-type-success">
    <div class="sn-toast">This is a success notification</div>
  </div>
</div>

You can use this to target these classes in your CSS to style the notifications.

/* override the css variables */
.sn-theme-dark {
  --sn-color-default: #fff;
  --sn-toast-bg-color: #121826;
  --sn-toast-text-color: #fff;
  --sn-dismiss-btn-color: #9ca3af;
  --sn-dismiss-btn-hover-color: #fff;
  --sn-progress-bar-color: #748aa8;
  --sn-icon-fill: #fff;
}

.sn-type-success {
  --sn-color-success: #34ab53;
}

/* or */

/* provide the styles directly */
.sn-toast-wrapper.sn-theme-dark {
  background-color: #121826;
}

.sn-theme-dark {
  color: #fff;
}

You can provide any string as the theme, and it will be injected into the toast wrapper as a class. The types however are limited to "default", "loading", "success", "error", "warning", and "info".

notify("This is a default notification", {
  type: "default",
  theme: "my-custom-theme",
});

will result in the following HTML:

<div class="sn-toaster">
  <div class="sn-toast-wrapper sn-theme-my-custom-theme sn-type-default">
    <div class="sn-toast">This is a default notification</div>
  </div>
</div>

Animations

The wrapper will also be provided with classes based on the state of the notification. The states are "entering", "idle", and "exiting", and are combined with the positionY and positionX props.

<div class="sn-toaster">
  <div
    class="sn-toast-wrapper sn-theme-dark sn-type-info sn-state-right-top-entering"
  >
    <div class="sn-toast">This is a notification</div>
  </div>
</div>

You can use these classes to animate the notifications.

.sn-state-right-top-entering,
.sn-state-right-bottom-entering {
  -webkit-animation: SNSlideInRight 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
  animation: SNSlideInRight 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

.sn-state-right-top-exiting,
.sn-state-right-bottom-exiting {
  -webkit-animation: SNSlideOutRight 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
  animation: SNSlideOutRight 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

Alternatively, you can provide your own classes that you want to use with the onEnter, onIdle, and onExit props.

<ToastProvider
  onEnter="my-enter-class"
  onIdle="my-idle-class"
  onExit="my-exit-class"
>
  <App />
</ToastProvider>

Classes as props

You can also provide your own classes or styles as props to the ToastProvider, Toaster, and when calling the notify or update function.

<ToastProvider
  wrapperClass="my-toast-wrapper"
  wrapperStyle={{ backgroundColor: "red" }}
  class="my-toast"
  style={{ color: "white" }}
  // etc
>
  <App />
</ToastProvider>

The dismiss button and progress bar can also be styled using the dismissButtonClass, dismissButtonStyle, progressBarClass, and progressBarStyle props.

Class and style props can also be provided as a function. The function will receive the theme and the type as arguments.

notify("This is a notification", {
  progressBarStyle: ({ type }) => {
    switch (type) {
      case "success":
        return { "background-color": "green" };
      case "error":
        return { "background-color": "red" };
      case "warning":
        return { "background-color": "orange" };
      case "info":
        return { "background-color": "blue" };
      case "loading":
        return { "background-color": "black" };
      default:
        return { "background-color": "gray" };
    }
  },
});

Custom toast

You can create custom toasts by providing a function as the first argument to the notify function (or as the content prop of the update function). The function will receive the toast class instance as an argument.

class Toast {
  store;
  toastConfig: Config;
  ref: HTMLElement | null = null;
  state: "entering" | "idle" | "exiting" = "entering";
  renderedAt: number | undefined;
  progressManager: ReturnType<typeof createProgressManager>;
  isPaused = true;
  isPausedByUser = false;
  offset = 0;

...
}

The function should return a JSX element that represents the custom toast.

notify(
  (toast) => {
    return (
      <div className="sn-toast">
        <div className="sn-icon">🚀</div>
        <div className="sn-content">
          <div className="sn-title">Custom Toast</div>
          <div className="sn-message">This is a custom toast</div>
        </div>
        <button className="sn-dismiss-btn" onClick={() => toast.dismiss()}>
          Dismiss
        </button>
      </div>
    );
  },
  {
    duration: 5000,
    type: "success",
  },
);

Custom progress bar

You can create custom progress bars by hooking into the progress signal returned by the notify or update function. The showProgressBar option should be set to false to prevent the default progress bar from being shown.

const { notify } = useToast();

const { progressControls } = notify(
  <div>
    <div>This is a toast with a custom progress bar</div>
    <div
      class="absolute left-0 top-0 h-full bg-blue-600/10"
      style={{ width: `${100 - progressControls.progress()}%` }}
    />
  </div>,
  {
    showProgressBar: false,
  },
);

If using a custom toast, the progress signal can be accessed via the progressManager property of the toast instance.

notify(
  (toast) => {
    return (
      <div className="sn-toast">
        <div>This is a custom toast with a custom progress bar</div>
        <div
          class="absolute left-0 top-0 h-full bg-blue-600/10"
          style={{ width: `${100 - toast.progressManager.progress()}%` }}
        />
      </div>
    );
  },
  {
    duration: 5000,
    type: "success",
  },
);

Show queue

An example of how to show a queue of notifications can be found in the getQueue guide.

Track Notification Dismissal Reasons

An example of how to show a reason why a notification was dismissed can be found in the dismiss guide.

Promise API

An example of how to use the promise API can be found in the promise guide.

Pause timer when the window loses focus

The toast timer will pause by default when the window loses focus. You can disable this behavior by setting the pauseOnWindowInactive option to false.

Don't render toasts when the window is not focused

Toasts will not be rendered when the window is not focused by default. You can disable this behavior by setting the renderOnWindowFocus option to true.

Drag to dismiss

Toast will be dismissed when dragged to the left or right of the screen by default. You can disable this behavior by setting the dragToDismiss option to false. Drag treshold can be adjusted by setting the dragTreshold option.

Custom dismiss button

You can create a custom dismiss buttons by using the id provided by the notify function. You should also disable the default dismiss button by setting the showDismissButton option to false.

const { notify, dismiss } = useToast();

const { id } = notify(
  <div>
    <p>This is a notification</p>
    <button onClick={() => notify.dismiss(id)}>Dismiss</button>
  </div>,
  {
    duration: 5000,
    showDismissButton: false,
  },
);

If using a custom toast, you can dismiss the toast by calling the dismiss method on the toast instance.

notify(
  (toast) => {
    return (
      <div className="sn-toast">
        <div>This is a custom toast</div>
        <button
          className="sn-dismiss-button"
          onClick={() => toast.dismiss("user dismissed")}
        >
          Dismiss
        </button>
      </div>
    );
  },
  {
    duration: 5000,
    type: "success",
  },
);

Play or pause the notification timer manually

The guide on how to play or pause the notification timer manually can be found in the play/pause guide.

If using a custom toast, you can pause the timer by calling the pause method on the progressManager of the toast instance.

notify(
  (toast) => {
    return (
      <div className="sn-toast">
        <div>This is a custom toast</div>
        <button onClick={() => toast.progressManager.pause()}>Pause</button>
      </div>
    );
  },
  {
    duration: 5000,
    type: "success",
  },
);

Keyboard shortcuts

You can use the Alt + T combination to focus a toast. Pressing Alt + T again will focus the next toast, and so on.

The toast that is currently focused can be dismissed by pressing Escape.

When a toast is focused, the progress timer will be paused. The timer will resume when the toast loses focus. If, however, the toast was paused by using the progressControls.pause() function, the timer will not resume on focus out. In that case, the timer can be resumed by progressControls.play().

You can try this out by pressing the button below and then pressing Alt + T.

© Copyright 2025 Solid Notifications

GitHub