PHPackages                             sparky-spa/sparky - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. sparky-spa/sparky

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

sparky-spa/sparky
=================

v1.1.0(4y ago)07[5 issues](https://github.com/sparky-spa/sparky/issues)MITJavaScriptPHP &gt;=7.2

Since May 27Pushed 4y ago1 watchersCompare

[ Source](https://github.com/sparky-spa/sparky)[ Packagist](https://packagist.org/packages/sparky-spa/sparky)[ RSS](/packages/sparky-spa-sparky/feed)WikiDiscussions master Synced yesterday

READMEChangelog (2)Dependencies (3)Versions (3)Used By (0)

 [![](https://camo.githubusercontent.com/87282545dbc11984f1b1bb42da6149e051874bd596fdbaa207a6dcd0a8acfa25/68747470733a2f2f692e696d6775722e636f6d2f33573777776d372e706e67)](https://sparky-spa.webxid.net)

The tool to develop Single Page Applications on PHP
===================================================

[](#the-tool-to-develop-single-page-applications-on-php)

Easy to start, easy to use

HOW TO USE
----------

[](#how-to-use)

### Install

[](#install)

Run `composer require sparky-spa/sparky`

#### Setup config

[](#setup-config)

Set up the settings

```
\SparkySpa\Sparky::config([
    // Mandatory properties
    'namespace' => 'App\SparkyComponent', // the namespace of your components
    'ajax_uri' => '', // endpoint for ajax request. It could be relate or absolute link.
    'view_callback' => function(string $view_name, array $data = []): string
    {
        // here you can use any views handler, blade, twig, handlebar etc.
        // Or, just implement the native PHP includes things
        return view($view_name, $data)
            ->render();
    },

    // Optional properties
    'return_jquery_element' => true, // TRUE by default. If TRUE, an event listener will receive `$(this)` otherwise `this`
    'is_dev_mode' => true, // FALSE by default. If TRUE, will display threw errors instead return 500 Internal Server Error
]);
```

#### Endpoint `ajax_uri` implementation

[](#endpoint-ajax_uri-implementation)

It has to support the next URIs

```
// POST /{$component_name}/{$action}/{$args}
// POST /{$component_name}/{$action}
// POST /{$component_name}

// GET /{\SparkySpa\Sparky::NAME_MINI_JS}
```

Also, use the function `handleHttpRequest()` to implement the endpoints correctly

##### For `POST /....` requests

[](#for-post-ajax_uri-requests)

```
use function SparkySpa\handleHttpRequest;

echo handleHttpRequest(
	$component_name,
	$action,
	$args,
	$post_body
);
```

##### For `GET /{Sparky::NAME_MINI_JS}` request

[](#for-get-ajax_urisparkyname_mini_js-request)

```
use function SparkySpa\handleHttpRequest;
use SparkySpa\Sparky;

echo handleHttpRequest(
	Sparky::NAME_MINI_JS
);
```

Feel free to use the tool 😉

Back-end
--------

[](#back-end)

### Implement a Component

[](#implement-a-component)

Let imagine, we have the component

```
namespace App\SparkyComponent;

use SparkySpa\Component;

class ChatCheckerComponent extends Component
{
    #region Actions

    /**
     * @inheritDoc
     */
    public function render()
    {
        return $this->view('spa/chat_checker');
    }

    #endregion
}
```

### Insert component into a page

[](#insert-component-into-a-page)

The all next variants will work correctly

```
use function SparkySpa\sparky;
use App\SparkyComponent\ChatCheckerComponent;

echo sparky('chat_checker', []);
echo sparky(ChatCheckerComponent::getName(), []);
echo ChatCheckerComponent::getTplBody([]);
```

If you place a component to an additional namespace (e.g. `User\ChatCheckerComponent`), use the next syntax

```
use function SparkySpa\sparky;

echo sparky('user.chat_checker');
```

### Component Actions

[](#component-actions)

Calling order of a component actions

```
$component->mount(); // it doesn't call in Ajax request

$component->beforeExecuting();

$response = $component->customAction(); // an emitted method

if (!is_string($response)) {
    $component->beforeRendering();

    $response = $component->render();
}

$component->afterRendering();
```

#### customAction

[](#customaction)

This is an action, which calls by `emit` actions.

Return a string to skip the `$component->render();` calling. The returned string will be a response onto an ajax request. In the case, the action `$component->beforeRendering();` will be skipped too. So, please, call it inside the `$component->customAction();`, if it needs.

Views
-----

[](#views)

### Emit component action

[](#emit-component-action)

#### onClick: emit action

[](#onclick-emit-action)

It makes request to back-end to an action

```

```

#### onClick: init event

[](#onclick-init-event)

It doesn't make request to back-end but trig an event/action listeners only

```

```

#### Emit action

[](#emit-action)

```
0s delay by default
trigger action in 750ms after loading

```

The time - is delay to an action will emit after the Sparky loading

### Init component event

[](#init-component-event)

#### Action on a page/component load

[](#action-on-a-pagecomponent-load)

The main different between `spa:emit` and `spa:event` is the last one inits an event listeners but not to call the component action on back-end

```
0s interval by default
trigger event in 750ms after loading

```

### Bind Component property to HTML field

[](#bind-component-property-to-html-field)

The `component_property_name` has to be public property of a component

```

```

JavaScript
----------

[](#javascript)

### Sparky load events

[](#sparky-load-events)

It's important to use the load events, because it's a safety way to prevent the error `Uncaught ReferenceError: Sparky is not defined`

```
document.addEventListener('SparkySpaLoad', function()
{
	// a code
});
```

#### Events list

[](#events-list)

**Inits once per a page load**

- `SparkySpaSetConfig` - Sparky config could not be set up at the moment. Please do not use the event if you`re not sure
- `SparkySpaBeforeInit` - the event after the config setting up
- `SparkySpaInit` - the all Sparky elements have been initiated

**Inits after a page loading and each time after a component receiving answer on an action request from back-end**

- `SparkySpaLoad` - inits before a component events queue will be process.

#### Emit component action in JS

[](#emit-component-action-in-js)

The next executions will call a component method

```
document.addEventListener('SparkySpaLoad', function()
{
	Sparky.emitTo('component_name', 'action_name');

	let data = [];

	Sparky.emitTo('component_name', 'action_name', data);

	Sparky.emitTo('component_name', 'action_name', [], () => {});

	// this emition will not replace a component html on the page
	Sparky.emitQuietlyTo('component_name', 'action_name', data, (component, response) => {
		// a code
	});
});
```

`action_name` - it's a component method name, which will call. It also is an `event_name` for listeners `data` - this is args list of `action_name` method `callback` - it will execute after an emit request will be done and before a listener calling

### Init component event

[](#init-component-event-1)

#### To init component event in JS

[](#to-init-component-event-in-js)

It also will not call a component method but inits the event listeners

```
document.addEventListener('SparkySpaLoad', function()
{
	Sparky.initEventTo('component_name', 'event_name');
	Sparky.initEventTo('component_name', 'event_name', []);
	Sparky.initEventTo('component_name', 'event_name', [], dom_element);

	Sparky.initEventAny('event_name'); // inits all events with `event_name` without any relation to a component.
	Sparky.initEventAny('event_name', []); // inits all events with `event_name` without any relation to a component.
	Sparky.initEventAny('event_name', [], dom_element); // inits all events with `event_name` without any relation to a component.
});
```

### Event/Action Listener in JS

[](#eventaction-listener-in-js)

Use the next things to listen an event

```
document.addEventListener('SparkySpaLoad', function()
{
	Sparky.on('component_name', 'event_name', (dom_element, event_data, component) => {});

	// listens all events with `event_name` without any relation to a component.
    	Sparky.onAny('event_name', (dom_element, event_data, component) => {
		if (!component.is('component_name')) {
			return;
        	}

		if (!dom_element) {
			// dom_element coould be null in 2 cases
            		// 1. There was calling `Sparky.initEventTo()` without `dom_element`
            		// 2. A component has been refreshed and the element was replaced with new one

			return Sparky.LISTENER_FORGET; // will remove the listener from a stack
		}

		// a code
    });
});
```

`event_name` - it's a component method name, which was called `component_name` - a component name of an event.

`event_data.response` - it will contain HTML body of response if an action (not event) was emitted quietly

> Note Do not check a component

#### Reserved event names

[](#reserved-event-names)

##### sparky:update\_binds

[](#sparkyupdate_binds)

`sparky:update_binds` - executes on a component property update by a bound tag.

```

```

This event pass an updated properties list to a listener

### WARNING

[](#warning)

> Please, do not pass secure data into a Component's public property. It passes to front-end and could be readed in browser

###  Health Score

20

—

LowBetter than 13% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity4

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~23 days

Total

2

Last Release

1474d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/3855639?v=4)[Pavlo M.](/maintainers/webxid)[@webxid](https://github.com/webxid)

---

Top Contributors

[![webxid](https://avatars.githubusercontent.com/u/3855639?v=4)](https://github.com/webxid "webxid (19 commits)")

### Embed Badge

![Health badge](/badges/sparky-spa-sparky/health.svg)

```
[![Health](https://phpackages.com/badges/sparky-spa-sparky/health.svg)](https://phpackages.com/packages/sparky-spa-sparky)
```

###  Alternatives

[facuz/laravel-themes

Theme will help you organize your themes inside Laravel projects easily and maintain its related assets, layouts and partials for the theme in single directory. (Based on teepluss/theme)

13744.0k2](/packages/facuz-laravel-themes)[ackintosh/snidel

A multi-process container. It looks like multi-thread-ish.

1051.2k](/packages/ackintosh-snidel)[infocyph/intermix

A lightweight PHP DI container, invoker, serializer, and utility toolkit.

137.7k2](/packages/infocyph-intermix)[heptacom/heptaconnect-portal-base

HEPTAconnect base dataset that every other portal is based on

1025.3k17](/packages/heptacom-heptaconnect-portal-base)[codespede/simple-multi-threader

122.6k](/packages/codespede-simple-multi-threader)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
