Another component likely needed within most applications is an alert, because at some point we’ll need to provide feedback to our users. So, let’s tackle an alert component.
💡 Small note - if you’re using Firefox, and you’re looking at the Pines UI alerts, you’ll notice the icon is overlapping the headline. This is just because they’re using the :has() pseudo selector to determine if there is an icon, and Firefox support for :has() is currently only in the nightly build. We’ll fix this in our component though.
Creating An Alert Demo Page
First, let’s create a new demonstration page for our alert component.
touch resources/views/pages/components/alert.edgeCopied!
Then, inside our new alert.edge page, let’s copy over the layout and base button markup from our button.edge page, changing “Button” to “Alert”.
@layout.app({ title: request.params().name }) <h3 class="font-bold">Base Alert</h3> <div x-data class="mb-8 space-x-3 space-y-3"> </div> @endCopied!
- resources
- views
- pages
- components
- alert.edge
Next, we’ll add this page to our components list inside our routes file.
const components = [ 'alert', 'button', ]Copied!
- start
- routes.ts
This will add it to the list of components we have on our home page.
Creating Our Base Alert
First, let’s give ourselves a place to work by creating a new alert folder with an index.edge file inside.
mkdir resources/views/components/alert touche resources/views/components/alert/index.edgeCopied!
Now let’s jump into the Pines UI alert documentation and give the base alert markup a copy, or you can copy it from below.
<div class="relative w-full rounded-lg border bg-white p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-nuetral-900"> <svg class="w-4 h-4" xmlns="<http://www.w3.org/2000/svg>" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"></polyline><line x1="12" x2="20" y1="19" y2="19"></line></svg> <h5 class="mb-1 font-medium leading-none tracking-tight">Alert Message Headline</h5> <div class="text-sm opacity-70">This is the subtext for your alert message, providing important information or instructions.</div> </div>Copied!
Then, let’s paste that inside of our new alert/index.edge file.
<div class="relative w-full rounded-lg border bg-white p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-nuetral-900"> <svg class="w-4 h-4" xmlns="<http://www.w3.org/2000/svg>" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"></polyline><line x1="12" x2="20" y1="19" y2="19"></line></svg> <h5 class="mb-1 font-medium leading-none tracking-tight">Alert Message Headline</h5> <div class="text-sm opacity-70">This is the subtext for your alert message, providing important information or instructions.</div> </div>Copied!
- resources
- views
- components
- alert
- index.edge
First, you might notice that our alert has three different distinct portions to it.
The SVG icon
The H5 heading
The DIV message
As we progress with our component, we may or may not want to utilize any one of these within our component, so we’ll make each one of these optional.
For now, though, let’s go ahead and add what we have for our base alert into the base alert section of our demo page.
@layout.app({ title: request.params().name }) <h3 class="font-bold">Base Alert</h3> <div x-data class="mb-8 space-x-3 space-y-3"> @alert() Default, Base Alert @end </div> @endCopied!
- resources
- views
- pages
- components
- alert.edge
Replacing the :has Pseudo Selector
Lastly, in this lesson, let’s fix the :has() pseudo selector since its support is still a little hit or miss.
On our alert’s outermost div, you should find the class [&:has(svg)]:pl-11, this is the class causing our svg and headline to overlap on browsers that don’t support :has(). This is essentially adding a pl-11 when the outermost div contains an svg element.
We can remedy this for now using a variable, but we’ll add an even better solution when we add our component’s slots.
++@set('showIcon', showIcon ?? true) <div class="relative w-full rounded-lg border bg-white p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] text-nuetral-900 {{ showIcon ? 'pl-11' : '' }}"> @if (showIcon) <svg class="w-4 h-4" xmlns="<http://www.w3.org/2000/svg>" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"></polyline><line x1="12" x2="20" y1="19" y2="19"></line></svg> @endif <div class="relative w-full rounded-lg border bg-white p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-nuetral-900"> <svg class="w-4 h-4" xmlns="<http://www.w3.org/2000/svg>" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"></polyline><line x1="12" x2="20" y1="19" y2="19"></line></svg> <h5 class="mb-1 font-medium leading-none tracking-tight">Alert Message Headline</h5> <div class="text-sm opacity-70">This is the subtext for your alert message, providing important information or instructions.</div> </div>Copied!
- resources
- views
- components
- alert
- index.edge
So, here we’re adding a variable called showIcon, allowing it as a prop and defaulting to true if it’s not provided. Then, we’re removing the [&:has(svg)]:pl-11 class and replacing it with a ternary that applies pl-11 if showIcon is truthy. Lastly, we’re wrapping the svg icon itself in an if check, only rendering it if showIcon is truthy.