Frontend#
Waterhole's frontend is made up of Laravel Blade views and components, and uses Hotwire to coordinate partial page updates.
Blade Components#
Waterhole exposes many Blade Components that you can use in your own views. These are documented in the Waterhole\View\Components
namespace.
Perhaps the most important of these to know is the <x-waterhole::layout>
component. Use this to render your own views inside the Waterhole layout:
<x-waterhole::layout title="Hello World">
<h1>Hello, world!</h1>
</x-waterhole::layout>
Blade Components are only used to encapsulate more complex HTML structures and behavior. For basic UI elements like buttons and inputs, use plain HTML elements and apply Waterhole's CSS classes directly.
Component Lists#
Many parts of Waterhole's templates render lists of components. For example, the page header is made up of these components:
You can hook into these component lists and add your own components, or remove existing ones. All of these component lists are exposed as extenders.
Check out the list of extenders to learn about all the points where you can modify components. The documentation for each extender also describes what parameters will be passed into the components when they're rendered.
Adding Components#
To add a component, call the add
method on the applicable extender in the extend
method of your service provider:
use Waterhole\Extend;
use App\Views\Components\HelloWorld;
Extend\SiteHeader::add(HelloWorld::class);
The component can be any one of the following:
- The name of a Blade Component class (e.g.
HelloWorld::class
) - A Blade Component instance (e.g.
new HelloWorld()
) - The name of a view (e.g.
waterhole.example
) - A callable that returns any of the above, which will be evaluated every time the list is rendered
Component Positions#
Each item in a component list has a "position", and components are rendered by their position in ascending order. To specify a position, pass it as a named argument. Otherwise, a default of 0
will be used.
Extend\SiteHeader::add(HelloWorld::class, position: 10);
Component Keys#
When adding a component to an extender, you can specify a unique key. This will allow other extensions to replace the component by using the same key, or remove it:
Extend\SiteHeader::add(HelloWorld::class, key: 'hello');
// Replace the existing `hello` component
Extend\SiteHeader::replace('hello', HelloWorld::class);
// Remove the `hello` component
Extend\SiteHeader::remove('hello');
Creating Component Lists#
If you're building an extension, you can expose your own extendable component lists. Create an extender using the Waterhole\Extend\Concerns\OrderedList
and OfComponents
traits and add any default components statically:
namespace Acme\Example\Extend;
use Waterhole\Extend\Concerns\OrderedList;
use Waterhole\Extend\Concerns\OfComponents;
class PortalHeader
{
use OrderedList, OfComponents;
}
PortalHeader::add(PortalTitle::class, -10);
Rendering Component Lists#
You can retrieve the ordered component instances using the components
method of an extender (passing in any props), and then use the @components
Blade directive to render them:
@components(Acme\Example\Extend\PortalHeader::components(['foo' => 'bar']))
Hotwire#
Waterhole uses Hotwire to achieve the speed and responsiveness of a single-page application, while rendering templates on the server.
The turbo-laravel library is included and can be used to help mark-up Turbo Frames and build Turbo Stream responses.
Stimulus & Custom Elements#
Waterhole's templates are all server-rendered HTML, progressively enhanced with sprinklings of JavaScript via both Stimulus and Custom Elements. Waterhole includes all the elements from the Inclusive Elements library.
Turbo Drive#
Turbo Drive accelerates links and form submissions by negating the need for full page reloads. It is enabled by default in all Waterhole views. If needed, you can opt out on individual links and forms.
Turbo Frames#
Turbo Frames allow predefined parts of a page to be updated on request. They are used in various places throughout the Waterhole UI. For example, a <turbo-frame>
wraps each comment so that when you click "Like" or "Edit", only that comment will be re-rendered.
You may need to be mindful of Turbo Frames when hooking into Waterhole's views. It is possible to force a link or form to "break out" of a frame if needed.
Turbo Streams#
Turbo Streams are fragments of HTML wrapped in <turbo-stream>
elements that specify where and how the HTML should be merged into the page. Waterhole uses Turbo Streams to deliver partial page updates after running Actions, and to broadcast real-time updates through WebSockets.
Streamable Components#
Waterhole includes a mechanism to simplify the process of rendering a Blade Component in a Turbo Stream. First, the component must include the Waterhole\View\Components\Concerns\Streamable
trait:
use Illuminate\View\Component;
use Waterhole\Models\Post;
use Waterhole\View\Components\Concerns\Streamable;
class PostTitle extends Component
{
use Streamable;
public function __construct(public Post $post)
{
}
public function render()
{
return <<<blade
<div {{ $attributes }}>
{{ $post->title }}
</div>
blade;
}
}
This trait exposes an id()
method on the component, and the $attributes
bag will automatically be populated with an id
attribute using this value. By default, the ID will be derived from the component name and the component's first public property that is a Model
instance ($post
in this example). You can override the method if you'd like to specify a custom ID.
To render a <turbo-stream>
element for the streamable component, use the Waterhole\Views\TurboStream
class. There is a method for each available Turbo Stream action. Pass in an instance of the streamable component:
use Waterhole\Views\TurboStream;
TurboStream::replace(new PostTitle($post));
TurboStream::remove(new PostTitle($post));
TurboStream::append(new PostTitle($post), '#target_id');
TurboStream::prepend(new PostTitle($post), '#target_id');
TurboStream::before(new PostTitle($post), '#target_id');
TurboStream::after(new PostTitle($post), '#target_id');
No Results Found