victorycodedev/toastkit

Rich, customizable native toast notifications for NativePHP Mobile.

Maintainers

Package info

github.com/victorycodedev/toastkit

Type:nativephp-plugin

pkg:composer/victorycodedev/toastkit

Transparency log

Statistics

Installs: 10

Dependents: 0

Suggesters: 0

Stars: 5

Open Issues: 0

v1.2.0 2026-08-29 19:42 UTC

This package is auto-updated.

Last update: 2026-08-29 19:46:32 UTC


README

Rich, customizable native toast notifications for NativePHP Mobile.

ToastKit renders toasts as native overlays — Jetpack Compose on Android, SwiftUI on iOS — so they look and feel like part of the operating system. No Blade component is required.

Table of Contents

Feature Highlights

  • Five variantssuccess, error, warning, info, and neutral.
  • Rich content — title, message, and icons with per-platform overrides.
  • Full customization — position, animation direction, progress, loading, swipe-to-dismiss, close control, colors, corner radius, padding, and shadow.
  • Action buttons — a native action button with its own ID and pressed event.
  • Queue strategy — FIFO, one toast at a time.
  • Stack strategy — up to maxVisible toasts on screen with FIFO overflow.
  • Live updates — change a visible or queued toast's message, variant, icon, style, or timer without creating a new toast.
  • Unique toasts — suppress duplicate work by a stable semantic key across visible, queued, stacked, and persistent toasts.
  • Idempotent dismissal — dismiss by ID or dismiss everything.
  • EventsToastShown, ToastDismissed, and ToastActionPressed.
  • JavaScript API — a fluent Toast API for web-facing apps.

Installation

Install the package with Composer:

composer require victorycodedev/toastkit

The service provider is auto-discovered by Laravel. Register the native code (only needed once per app):

php artisan vendor:publish --tag=nativephp-plugins-provider
php artisan native:plugin:register victorycodedev/toastkit

Verify it is registered:

php artisan native:plugin:list

Then rebuild your app, since Swift and Kotlin are compiled into it:

php artisan native:run

Quick Start

use Victorycodedev\ToastKit\Facades\Toast;

Toast::success('Changes saved')->show();

ToastKit is fully customizable:

Toast::make('Profile updated')
    ->title('Success')
    ->success()
    ->icon('check')
    ->position('top')
    ->duration(3000)
    ->animation('spring')
    ->swipeToDismiss()
    ->show();

ToastKit is controlled from PHP and renders as a native overlay — you never add a Blade component.

Basic Toasts

Toast::success('Saved')->show();
Toast::error('Something went wrong')->show();
Toast::warning('Storage almost full')->show();
Toast::info('Downloading...')->show();
Toast::neutral('Copied')->show();

Each variant applies sensible native defaults, which any explicit style option overrides.

Custom Toasts

Toast::make('Download complete')
    ->title('invoice.pdf')
    ->success()
    ->icon('check')
    ->position('top')
    ->background('#111827')
    ->foreground('#FFFFFF')
    ->iconColor('#22C55E')
    ->cornerRadius(18)
    ->padding(16)
    ->shadow()
    ->animation('spring')
    ->swipeToDismiss()
    ->duration(3000)
    ->show();

Supported options include title(), icon(), position(), duration(), persistent(), animation(), direction(), progress(), loading(), swipeToDismiss(), dismissible(), action(), and the styling methods background(), foreground(), iconColor(), actionColor(), cornerRadius(), padding(), and shadow(). See the API Reference for the full list.

Icons

icon() accepts the same icon names as NativePHP's <native:icon> component, so any icon you already use in your Blade views works unchanged:

Toast::make('Download complete')->icon('check')->show();
Toast::make('New message')->icon('email')->show();
Toast::make('Storage full')->icon('warning')->show();

A shared name resolves per platform automatically — SF Symbols on iOS and Material Icons on Android.

Platform overrides

When each platform needs a different symbol, pass the platform-native name directly:

Toast::make('Saved')
    ->icon(
        'check',
        ios: 'checkmark.circle.fill', // SF Symbol
        android: 'done',              // Material Icon ligature
    )
    ->show();
  • ios: — an SF Symbol name (dotted, e.g. house.fill, checkmark.circle.fill).
  • android: — a Material Icon ligature name (underscored, e.g. shopping_cart, qr_code_2).

You can pass either override on its own:

Toast::make('Rated')->icon(ios: 'star.fill')->show();

See NativePHP's Icon name reference for the names guaranteed to work consistently on both platforms.

Typography

Customize the message and title typography independently with text() and titleText(). Every argument is optional — anything left unset falls back to the native defaults (message: base size, medium weight, left-aligned, non-italic; title: left-aligned, non-italic, semibold weight):

Toast::make('Your download is complete')
    ->title('Download complete')
    ->text(
        font: 'Inter',
        size: 'sm',
        weight: 'normal',
    )
    ->titleText(
        size: 'lg',
        weight: 'bold',
    )
    ->success()
    ->show();
Option Values
font A font name resolvable by the platform.
size xs, sm, base, lg, xl
weight normal, medium, semibold, bold
align left, center, right
italic true or false

Typed enums are available too — ToastTextSize, ToastTextWeight, ToastTextAlign:

use Victorycodedev\ToastKit\Enums\ToastTextAlign;
use Victorycodedev\ToastKit\Enums\ToastTextSize;
use Victorycodedev\ToastKit\Enums\ToastTextWeight;

Toast::make('Saved')
    ->text(
        size: ToastTextSize::Small,
        weight: ToastTextWeight::Medium,
        align: ToastTextAlign::Center,
    )
    ->show();

Typography updates follow the same sparse rules as the rest of update() — only the supplied values change:

Toast::update($id)
    ->message('Download complete')
    ->text(weight: 'semibold')
    ->success()
    ->show();

This changes only the message weight; font, size, align, and italic are left untouched.

Font resolution

font delegates to NativePHP's font resolver, so it honors the fonts array in config/native-ui.php. Pass a bundled font file's basename (Inter-Bold) or a config alias (accent, body, headline, …) and ToastKit renders the typeface your app already configured:

Toast::make('Saved')->text(font: 'accent')->show();

A name that can't be resolved falls back to the system font on both platforms. ToastKit does not bundle, download, or register fonts itself — it renders whatever NativePHP resolves.

Updating Toasts

update() changes a visible or queued toast in place, keeping the same ID:

$id = Toast::info('Uploading file...')
    ->persistent()
    ->show();

// Later...
Toast::update($id)
    ->message('Upload complete')
    ->success()
    ->icon('check')
    ->duration(2000)
    ->show();

Unique Toasts

Use unique() when one logical operation should have at most one active toast, even if the toast is currently visible, queued, stacked, or persistent:

$id = Toast::info('Syncing contacts...')
    ->unique('contacts-sync')
    ->persistent()
    ->show();

The key identifies the operation, not the presentation. ToastKit does not deduplicate ordinary toasts by message. Showing the same unique key again is ignored: it does not replace or update the original toast, reset its timer, move it in a queue, or emit another ToastShown event. show() returns the original toast's UUID, so callers can safely keep using the result:

$originalId = Toast::info('Syncing...')->unique('contacts-sync')->show();
$sameId = Toast::success('Duplicate request')->unique('contacts-sync')->show();

// $sameId === $originalId; the original toast is unchanged.

Update or dismiss the active toast without retaining its UUID:

Toast::updateUnique('contacts-sync')
    ->success()
    ->message('Contacts synced')
    ->duration(2000)
    ->show();

Toast::dismissUnique('contacts-sync');

A key remains reserved until the toast has fully left the screen, including its exit animation. It is then reusable after every terminal path: timeout, swipe, action, close/programmatic dismissal, replacement, queue overflow, or dismissAll(). Updating a toast never changes its unique key. Calling updateUnique() or dismissUnique() for a key that is not active throws ToastKitException.

Unique keys also work with presets. Define the key as part of the preset during application boot when that preset represents one specific operation:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Victorycodedev\ToastKit\PendingToast;
use Victorycodedev\ToastKit\Facades\Toast;

final class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Toast::definePreset('contacts-sync', fn (PendingToast $toast) => $toast
            ->info()
            ->unique('contacts-sync')
            ->persistent()
            ->loading());
    }
}

The unique key is already included, so callers only use the preset and add any per-toast configuration they need:

Toast::preset('contacts-sync')
    ->message('Syncing contacts...')
    ->show();

Updates are sparse:

  • The toast keeps its original ID.
  • Only properties you explicitly set change; everything else is preserved.
  • A persistent toast becomes timed once you supply a duration().

A message-only update is ideal for live progress:

Toast::update($id)
    ->message('Uploading 50%...')
    ->show();

Native Appearance

ToastKit uses its fully customizable renderer on both platforms by default. Call native() when you want each operating system's current design language instead:

// Native appearance on iOS and Android.
Toast::success('Saved')
    ->native()
    ->show();

// Native iOS, custom ToastKit Android.
Toast::success('Saved')
    ->native(ios: true, android: false)
    ->show();

// Custom ToastKit iOS, native Android.
Toast::success('Saved')
    ->native(ios: false, android: true)
    ->show();

Native mode prioritizes platform appearance. Message, title, variant, icon, action, position, duration, persistence, unique identity, queue/stack behavior, progress, loading, dismissal controls, and swipe behavior remain available. ToastKit-specific colors, typography, corner radius, padding, shadow, animation, and direction are ignored only on a platform where native mode is enabled.

Custom styles are retained in the configuration; native() is not a reset. This lets one platform remain fully customized:

Toast::make('Saved')
    ->background('#000000')
    ->native(ios: true, android: false)
    ->show();

Here iOS uses the system appearance while Android uses ToastKit's custom black appearance. Calling background() before or after native() produces the same result. Use native(ios: false, android: false) to explicitly select the custom renderer on both platforms.

Renderer selection is preserved by sparse updates and can also be changed safely on an existing toast:

Toast::update($id)
    ->native(ios: false, android: true)
    ->show();

On iOS 26 and later, ToastKit uses Apple's system Liquid Glass effect. Earlier supported iOS versions use SwiftUI's native regular material. Android uses the official Material 3 Snackbar component inside ToastKit's existing overlay, retaining the established lifecycle and event pipeline.

Progress & Loading

Use determinate progress for work with a known percentage. Values are clamped to 0100, and updates animate without replacing the toast:

$id = Toast::info('Uploading...')->persistent()->progress(0)->show();

Toast::update($id)->progress(42.5)->show();
Toast::update($id)->progress(100)->message('Upload complete')->show();

Use loading() when progress is unknown, and loading(false) to stop it:

$id = Toast::info('Connecting...')->persistent()->loading()->show();
Toast::update($id)->loading(false)->message('Connected')->duration(1500)->show();

If a payload contains both progress and loading: true, determinate progress wins. This makes partial updates deterministic while preserving both values in the transport contract.

Animations & Direction

ToastKit supports fade, slide, scale, spring, snap, pop, reveal, and bounce. Direction is independent and accepts auto, left, right, top, or bottom:

Toast::success('Published')
    ->animation('bounce')
    ->direction('right')
    ->show();

auto is the default and derives the motion from the toast position. Reduced-motion platform settings use a short fade instead of spatial or spring motion.

Presets

Define reusable presets during application boot, such as in a service provider:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Victorycodedev\ToastKit\PendingToast;
use Victorycodedev\ToastKit\Facades\Toast;

final class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Toast::definePreset('syncing', fn (PendingToast $toast) => $toast
            ->message('Syncing...')
            ->info()
            ->persistent()
            ->loading());
    }
}

Each call creates a fresh builder, and options chained afterward override the preset:

Toast::preset('syncing')->message('Syncing contacts...')->show();

Defining the same name again replaces the previous definition. Missing presets throw PresetNotFoundException. All intentional public configuration failures extend ToastKitException. Presets are PHP-only because they are registered in the Laravel application lifecycle.

Small applications can keep these definitions directly in AppServiceProvider::boot(). For larger applications, a convenient optional organization is an App\Toasts\ToastPresets class with a static register() method, called from AppServiceProvider::boot(). ToastKit does not generate or require this class; it simply keeps a longer preset catalog out of the provider. Precedence is: ToastKit defaults → preset → per-toast configuration → sparse update configuration.

namespace App\Toasts;

use Victorycodedev\ToastKit\Facades\Toast;

final class ToastPresets
{
    public static function register(): void
    {
        Toast::definePreset('payment-success', fn ($toast) => $toast
            ->success()->icon('check_circle')->animation('reveal')
            ->position('top')->duration(3000));

        Toast::definePreset('payment-failed', fn ($toast) => $toast
            ->error()->icon('error')->animation('snap')->direction('left')
            ->position('top')->duration(5000));

        Toast::definePreset('uploading', fn ($toast) => $toast
            ->info()->loading()->persistent());
    }
}

Then call ToastPresets::register() from your application's AppServiceProvider::boot():

namespace App\Providers;

use App\Toasts\ToastPresets;
use Illuminate\Support\ServiceProvider;

final class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        ToastPresets::register();
    }
}

You may instead keep all toast presets in a dedicated service provider, such as ToastServiceProvider:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Victorycodedev\ToastKit\PendingToast;
use Victorycodedev\ToastKit\Facades\Toast;

final class ToastServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Toast::definePreset('payment-success', fn (PendingToast $toast) => $toast
            ->success()
            ->icon('check_circle')
            ->animation('reveal')
            ->position('top')
            ->duration(3000));

        Toast::definePreset('payment-failed', fn (PendingToast $toast) => $toast
            ->error()
            ->icon('error')
            ->animation('snap')
            ->direction('left')
            ->position('top')
            ->duration(5000));

        Toast::definePreset('uploading', fn (PendingToast $toast) => $toast
            ->info()
            ->loading()
            ->persistent());
    }
}

Register that provider using your Laravel application's normal provider registration, for example in bootstrap/providers.php:

return [
    App\Providers\AppServiceProvider::class,
    App\Providers\ToastServiceProvider::class,
];

Exceptions

ToastKit exposes one package-owned exception hierarchy:

RuntimeException
└── ToastKitException
    ├── InvalidToastConfigurationException
    └── PresetNotFoundException

Catch ToastKitException when you want to handle every error intentionally raised by ToastKit:

use Victorycodedev\ToastKit\Exceptions\ToastKitException;

try {
    Toast::preset('payment-success')->message('Paid')->show();
} catch (ToastKitException $exception) {
    report($exception);
}

Use a specific subclass when the application can recover from one particular condition, such as a missing preset:

use Victorycodedev\ToastKit\Exceptions\PresetNotFoundException;

try {
    Toast::preset('payment-success');
} catch (PresetNotFoundException $exception) {
    // The requested preset was not registered.
}

Migrating exception catches

ToastKit exceptions no longer extend PHP's InvalidArgumentException. Applications that previously caught that exception for ToastKit calls should use the package base exception instead:

// Before
catch (\InvalidArgumentException $exception) {
    // ...
}

// Now
catch (\Victorycodedev\ToastKit\Exceptions\ToastKitException $exception) {
    // ...
}

Dismissing Toasts

$id = Toast::info('Syncing...')
    ->persistent()
    ->show();

Toast::dismiss($id);

Dismiss everything at once:

Toast::dismissAll();

Dismissals are idempotent — dismissing an ID that is already gone is a no-op.

Actions & Events

Add a native action button and handle its press:

use Native\Mobile\Attributes\On;
use Victorycodedev\ToastKit\Events\ToastActionPressed;

Toast::error('Connection lost')
    ->action(
        label: 'Retry',
        id: 'retry',
    )
    ->show();

#[On(ToastActionPressed::class)]
public function handleToastAction(
    string $toastId,
    string $actionId,
): void {
    if ($actionId === 'retry') {
        $this->retry();
    }
}

Pressing an action emits ToastActionPressed and dismisses the toast.

The other events follow the same pattern:

use Native\Mobile\Attributes\On;
use Victorycodedev\ToastKit\Events\ToastShown;
use Victorycodedev\ToastKit\Events\ToastDismissed;

#[On(ToastShown::class)]
public function handleToastShown(string $toastId): void
{
    // The toast is now visible.
}

#[On(ToastDismissed::class)]
public function handleToastDismissed(string $toastId, string $reason): void
{
    // $reason is one of: timeout, swipe, programmatic, action.
}

See Events for the full event reference.

Queue & Stack

The default strategy is a FIFO queue — one toast at a time:

Toast::info('First')->queue()->show();
Toast::info('Second')->queue()->show();

Each toast appears after the previous one finishes. Its duration only begins once it becomes visible.

The stack strategy shows up to maxVisible toasts at once:

Toast::success('Saved')
    ->stack()
    ->maxVisible(3)
    ->show();

When the stack is full, additional toasts wait and are admitted in FIFO order as existing toasts dismiss.

JavaScript Usage

ToastKit ships a JavaScript library in resources/js/ (Composer-installed at vendor/victorycodedev/toastkit/resources/js/). There is no published npm package — copy the files into your app or bundle them with your build tool.

import { Toast } from './resources/js';

Toast.success('Saved').show();

Updates mirror the PHP API:

const id = await Toast.info('Uploading...')
    .persistent()
    .show();

await Toast.update(id)
    .message('Upload complete')
    .success()
    .duration(2000)
    .show();

await Toast.dismiss(id);
await Toast.dismissAll();

Unique toasts have the same semantics in JavaScript:

const id = await Toast.info('Syncing contacts...')
    .unique('contacts-sync')
    .persistent()
    .show();

await Toast.updateUnique('contacts-sync')
    .success()
    .message('Contacts synced')
    .duration(2000)
    .show();

await Toast.dismissUnique('contacts-sync');

Raw bridge functions are also exported:

import { Show, Update, UpdateUnique, Dismiss, DismissUnique, DismissAll } from './resources/js';

await Show({ id: 'one', message: 'Hello' });
await Update('one', { message: 'Done' });
await UpdateUnique('contacts-sync', { message: 'Done' });
await Dismiss('one');
await DismissUnique('contacts-sync');
await DismissAll();

Complete NativeComponent Example

<?php

namespace App\Screens;

use Native\Mobile\Attributes\On;
use Native\Mobile\Edge\NativeComponent;
use Victorycodedev\ToastKit\Events\ToastActionPressed;
use Victorycodedev\ToastKit\Facades\Toast;

class ToastDemoScreen extends NativeComponent
{
    public ?string $toastId = null;

    public function startUpload(): void
    {
        $this->toastId = Toast::info('Uploading...')
            ->persistent()
            ->show();
    }

    public function updateUpload(): void
    {
        if (! $this->toastId) {
            return;
        }

        Toast::update($this->toastId)
            ->message('Uploading 50%...')
            ->show();
    }

    public function completeUpload(): void
    {
        if (! $this->toastId) {
            return;
        }

        Toast::update($this->toastId)
            ->message('Upload complete')
            ->success()
            ->icon('check')
            ->duration(2000)
            ->show();
    }

    public function dismissToast(): void
    {
        if ($this->toastId) {
            Toast::dismiss($this->toastId);
        }
    }
}

Blade screen using native components:

<native:scroll-view>
    <native:column>
        <native:text>ToastKit Demo</native:text>

        <native:button
            label="Start"
            @press="startUpload"
        />

        <native:button
            label="Update"
            @press="updateUpload"
        />

        <native:button
            label="Complete"
            @press="completeUpload"
        />

        <native:button
            label="Dismiss"
            @press="dismissToast"
        />
    </native:column>
</native:scroll-view>

Real-world Example with NativePHP Fetch

ToastKit pairs naturally with the Fetch (Http) package for upload/download progress. Fetch is not a ToastKit dependency - this is an optional integration example.

$toastId = Toast::info('Downloading...')
    ->persistent()
    ->show();

$request = Fetch::timeout(120);

$this->requestId = $request->id();

$request->download(/* ... */);

Then handle the Fetch events to drive live toast updates:

use Native\Mobile\Attributes\On;
use Victorycodedev\ToastKit\Facades\Toast;

#[On(FetchDownloadProgress::class)]
public function onDownloadProgress(
    string $requestId,
    int $bytesReceived,
    ?int $bytesTotal,
    ?float $progress,
): void {
    if ($progress === null || ! $this->toastId) {
        return;
    }

    Toast::update($this->toastId)
        ->message(
            'Downloading '.(int) round($progress * 100).'%...'
        )
        ->show();
}

#[On(FetchDownloadCompleted::class)]
public function onDownloadCompleted(): void
{
    Toast::update($this->toastId)
        ->message('Download complete')
        ->success()
        ->icon('check')
        ->duration(2000)
        ->show();
}

#[On(FetchRequestFailed::class)]
public function onDownloadFailed(): void
{
    Toast::update($this->toastId)
        ->message('Download failed')
        ->error()
        ->duration(3000)
        ->show();
}

Refer to your Fetch package's documentation for its exact API surface.

Events

ToastKit dispatches three events. Listen with NativePHP's #[On] attribute:

Event Payload
Victorycodedev\ToastKit\Events\ToastShown toastId (string)
Victorycodedev\ToastKit\Events\ToastDismissed toastId (string), reason (string)
Victorycodedev\ToastKit\Events\ToastActionPressed toastId (string), actionId (string)
use Native\Mobile\Attributes\On;
use Victorycodedev\ToastKit\Events\ToastDismissed;

#[On(ToastDismissed::class)]
public function handleToastDismissed(string $toastId, string $reason): void
{
    // $reason is one of: timeout, swipe, programmatic, action.
}

ToastDismissReason declares timeout, swipe, programmatic, action, and replaced; the native renderers currently emit timeout, swipe, programmatic, and action.

Testing

Run the PHP suite:

./vendor/bin/pest

Run the JavaScript suite:

node --test resources/js/tests/*.test.js

ToastKit registers FakeBridge macros so your own tests can assert on toast traffic using domain vocabulary — no emulator or device required:

use Native\Mobile\Testing\Native;

Native::test(ProfileScreen::class)
    ->call('save')
    ->assertToastShownWithMessage('Profile updated');

Available macros:

Macro Description
assertToastShown(?callable $filter = null) A ToastKit.Show call was made.
assertToastShownWithMessage(string $message) A toast with the given message was shown.
assertToastShownWithId(string $id) A toast with the given ID was shown.
assertToastUpdated(string $id, ?callable $changesFilter = null) A toast was updated with the given ID.
assertToastDismissed(string $id) A toast with the given ID was dismissed.
assertAllToastsDismissed() ToastKit.DismissAll was called.

To test how a screen reacts to a ToastKit event, deliver the event yourself with NativePHP's emitNative():

use Native\Mobile\Testing\Native;
use Victorycodedev\ToastKit\Events\ToastActionPressed;

Native::test(ProfileScreen::class)
    ->emitNative(ToastActionPressed::class, [
        'toastId' => 'one',
        'actionId' => 'retry',
    ])
    ->assertSet('retried', true);

API Reference

Toast facade

Method Description
Toast::make(?string $message = null) Start building a toast.
Toast::success(string $message) A success-variant toast.
Toast::error(string $message) An error-variant toast.
Toast::warning(string $message) A warning-variant toast.
Toast::info(string $message) An info-variant toast.
Toast::neutral(string $message) A neutral-variant toast.
Toast::definePreset(string $name, Closure $preset) Define or replace a reusable PHP preset.
Toast::preset(string $name) Create a fresh builder from a preset.
Toast::update(string $id) Start building an update for an existing toast.
Toast::updateUnique(string $key) Start building an update resolved by an active unique key.
Toast::dismiss(string $id) Dismiss a toast by ID.
Toast::dismissUnique(string $key) Dismiss the active toast resolved by a unique key.
Toast::dismissAll() Dismiss all active and queued toasts.

PendingToast builder

make() and the variant shortcuts return a PendingToast. All methods are chainable; show() sends the toast to the native bridge and returns its ID (a UUID by default, or a custom ID from id()).

Method Description
id(string $id) Set a custom ID instead of the generated UUID.
unique(string $key) Reserve a semantic key and suppress duplicates until the toast fully exits.
message(string $message) Set the message text (required).
title(?string $title) Set or clear an optional title.
text(?string $font = null, $size = null, $weight = null, $align = null, ?bool $italic = null) Configure message typography. See Typography.
titleText(?string $font = null, $size = null, $weight = null, $align = null, ?bool $italic = null) Configure title typography. See Typography.
success() / error() / warning() / info() / neutral() Set the variant.
variant(ToastVariant|string $variant) Set the variant by enum or string.
icon(?string $name = null, ?string $ios = null, ?string $android = null) Set an icon using string names, with optional SF Symbol (ios:) / Material Icon (android:) overrides. See Icons.
position(ToastPosition|string $position) top, center, or bottom.
native(bool $ios = true, bool $android = true) Use platform-native appearance selectively; custom rendering remains the default.
duration(int $milliseconds) Set the visible duration (makes the toast timed).
persistent(bool $persistent = true) Make the toast persistent (no timeout).
animation(ToastAnimation|string $animation) fade, slide, scale, spring, snap, pop, reveal, or bounce.
direction(ToastDirection|string $direction) auto, left, right, top, or bottom.
progress(int|float $progress) Set determinate progress, clamped to 0100.
loading(bool $loading = true) Enable or disable indeterminate progress.
swipeToDismiss(bool $enabled = true) Enable or disable swipe-to-dismiss.
dismissible(bool $enabled = true) Show a visible close control.
action(string $label, string $id) Add an action button with a label and ID.
background(string $color) Set the background color.
foreground(string $color) Set the text color.
iconColor(string $color) Set the icon color.
actionColor(string $color) Set the action button color.
cornerRadius(float $radius) Set the corner radius.
padding(float $padding) Set the inner padding.
shadow(bool $enabled = true) Enable or disable the shadow.
queue() Use the queue strategy (one toast at a time).
stack() Use the stack strategy (multiple toasts on screen).
strategy(ToastStrategy|string $strategy) Set the strategy by enum or string.
maxVisible(int $count) Set the maximum visible stack size.
show() Send the toast to the native bridge and return its ID.

PendingToastUpdate builder

Toast::update($id) and Toast::updateUnique($key) return a PendingToastUpdate. It exposes the same configuration methods as PendingToast — except id() and unique(), since identity is fixed — plus a show() method that applies the update. Only properties you explicitly set are sent; everything else is preserved.

Enums

Enum Values
ToastVariant success, error, warning, info, neutral
ToastPosition top, center, bottom
ToastAnimation fade, slide, scale, spring, snap, pop, reveal, bounce
ToastDirection auto, left, right, top, bottom
ToastStrategy queue, stack
ToastTextSize xs, sm, base, lg, xl
ToastTextWeight normal, medium, semibold, bold
ToastTextAlign left, center, right
ToastDismissReason timeout, swipe, programmatic, action, replaced

Defaults

Property Default
variant neutral
position bottom
duration 3000 ms
persistent false
animation scale
direction auto
loading false
swipe_to_dismiss true
dismissible false
strategy queue
max_visible 3
corner_radius 16
padding 16
shadow true

Compatibility

Requirement Version
PHP 8.4+
NativePHP Mobile 4.1+
Android API 29+ (Android 10)
iOS 18.0+

ToastKit supports Android and iOS.

Permissions & Dependencies

ToastKit requires no Android permissions and no iOS permission strings. It adds no third-party native dependencies — it relies on the NativePHP host toolchain and the native platform frameworks (Jetpack Compose and SwiftUI).

Contributing

See CONTRIBUTING.md.

License

The MIT License (MIT). See LICENSE.