Components Basics

Creating

To create a new component all you have to do is just to create two files with the same name: ComponentName.html for template and ComponentName.php for code logic.

Please note: both files should be in the same folder.

Inside your php file create a class derived from Viewi\Components\BaseComponent

For example, let's create Counter component.

viewi-app/Components/Views/Counter/Counter.php

<?php

namespace Components\Views\Counter;

use Viewi\Components\BaseComponent;

class Counter extends BaseComponent
{
    public int $count = 0;

    public function increment()
    {
        $this->count++;
    }
}

viewi-app/Components/Views/Counter/Counter.html

<button (click)="increment">Clicked $count times.</button>

From now on you can use it as a tag with the same name as your class name: <Counter />

Reusing Components

You can reuse components as many times as you want. Each of them will have their own scope of data and reactive flow. For example:

<Counter />
<Counter />
<Counter />

The result:

Passing Data through Properties

You can pass data to the child component using html attributes. It can pass literals like strings, numbers, booleans or you can pass an expression.

For example, let's create HelloMessage component:

<?php

namespace Application\Components\Views\Demo;

use Viewi\Components\BaseComponent;

class HelloMessage extends BaseComponent
{
    public string $name;
}
<div>Hello $name</div>

And now we can pass data to the component as a custom attribute:

<HelloMessage name="John Smith" />
<HelloMessage name="Viewi" />
<HelloMessage name="{getFullName()}" />

The result:

Hello John Smith
Hello Viewi
Hello Bruce Wayne

Dynamic Components

In case you want to define your component name dynamically at runtime you can use dynamic component syntax.

For example:

class ComponentsBasics extends BaseComponent
{
    public $currentPage = 'HelloMessage';
}
<$currentPage name="Dynamic Component" />

The result:

Hello Dynamic Component

Slots

Quite often you will need to pass the content into child component through inner HTML like this:

<Notification>
    <i>Karolina</i> sent you a message.
</Notification>

This can be easily achieved with a special slot tag, like this:

Notification.html

<div>
    <strong>New notification:</strong>
    <slot></slot>
</div>

The result:

New notification: Karolina sent you a message.

Named Slots

Sometimes you will need to pass different contents into different places to render. A good example for this case is layout. Consider we want something like this:

<div class="header">
    <!-- header content here -->
</div>
<main>
    <!-- main content here -->
</main>
<footer>
    <!-- footer content here -->
</footer>

For that cases a slot tag can be used with a name attribute to define where each content belongs to. To specify content for each slot use slotContent tag with a name attribute.

Content from slotContent goes to slot with the same name. The rest of the content (outside slotContent) goes to slot without name attribute (slot by default).

For example:

BaseLayout.html

<div class="header">
    <slot name="header"></slot>
</div>
<main>
    <slot></slot>
</main>
<footer>
    <slot name="footer"></slot>
</footer>

Using BaseLayout:

<BaseLayout>
    <slotContent name="header">
        This is my header content
    </slotContent>
    <p>
        Some blog post
    </p>
    <slotContent name="footer">
        <p>Some footer links and copyright</p>
    </slotContent>
</BaseLayout>

The result:

This is my header content

Some blog post

Some footer links and copyright

Fallback Content

You can set a default content in case if no content is provided. Just place fallback content inside a slot tag:

<button>
    <slot>Submit</slot>
</button>

Then use it without content:

<SubmitButton></SubmitButton>

Will generate:

Or with provided content:

<SubmitButton>
    Save
</SubmitButton>

Will generate:

Using with if and foreach

You can use foreach with components as well as if, else, else-if:

Let's say you have a PostComponent component:

class PostComponent extends BaseComponent
{
    public string $content;
}
<p>$content</p>

You can use it with foreach:

class ComponentsBasics extends BaseComponent
{
    public array $posts = [
        'Viewi is awesome!',
        'Lorem ipsum dolor sit amet'
    ];
}
<PostComponent foreach="$posts as $post" content="$post"></PostComponent>

Will generate:

Viewi is awesome!

Lorem ipsum dolor sit amet

And this:

<PostComponent if="true" content="Viewi is awesome!"></PostComponent>

Will generate:

Viewi is awesome!