Our first component, excluding the layout component we created earlier, is going to be a button. The particular button we’ll be creating today will serve as our base button. Meaning, the different styles we’ll be creating in later lessons will derive from this base button.
Creating Our Component File
First, lets create an index.edge file inside a folder called button. This will allow us to directly call @button to use our component as EdgeJS will include index.edge in it’s search paths.
touch resources/views/components/button/index.edgeCopied!
Getting Our Button Markup
Next, let’s grab the button markup from PinesUI, just click the copy button (or you can copy the markup below) and paste it into our new button/index.edge file.
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none"> Button </button>Copied!
- resources
- views
- components
- button
- index.edge
Let’s leave this as-is for right now, and replace our placeholder text within our button demonstration page.
@layout.app({ title: request.params().name }) <h3 class="font-bold">Base Button</h3> <div class="mb-8 space-x-3 space-y-3"> @button() Base Button @end Button goes here </div> @endCopied!
- resources
- views
- pages
- components
- buttons.edge
Now, we haven’t added a slot yet to our button, so the “Base Button” content we’ve provided to our button won’t show, but you should now see our base button on the demonstration page.
Rendering Content
Buttons can have a plethora of different types of content. So, let’s use a main slot to add support for custom content.
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none"> {{{ await $slots.main() }}} Button </button>Copied!
- resources
- views
- components
- button
- index.edge
Button Types
One essential attribute to support is the type attribute. You’ll almost always want your button to either be a type of button or a type of submit. The button markup we copied earlier already has this attribute in place, set as button, so we can just simply keep that as the default value, but also allow a type prop to be passed in to customize this.
<button type="{{ type || 'button' }}" type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none"> {{{ await $slots.main() }}} </button>Copied!
- resources
- views
- components
- button
- index.edge
Our types now look like the below
@!button() {{-- type="button" --}} @!button({ type: 'button' }) {{-- type="button" --}} @!button({ type: 'submit' }) {{-- type="submit" --}}Copied!
Other Attributes
There’s also a number of other important attributes that you may want to include on your button, like form, aria attributes, etc. For these, we’ll use the serialize except prop so that we can define them as needed on our button usages.
<button {{ $props.serializeExcept(['type']) }} type="{{ type || 'button' }}" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none"> {{{ await $slots.main() }}} </button>Copied!
- resources
- views
- components
- button
- index.edge
Now we can add any attribute we’d like onto our button directly via the props. For example, if you need your button to reside outside the form, but still submit the form we can do the following.
<form id="loginForm" action="{{ route('login')" method="POST" ></form> @button({ type: 'submit', form: 'loginForm' }) Login @endCopied!
Extendable Class List
Lastly, let’s make our class list extendable. Since we already have a number of classes on our button already, we’ll want to directly plop the class prop within our pre-existing class list. We’ll also want to add “class” to our serialize except list.
<button {{ $props.serializeExcept(['type', 'class']) }} {{ $props.serializeExcept(['type']) }} type="{{ type || 'button' }}" class="{{ $props.class }} inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none"> class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none"> {{{ await $slots.main() }}} </button>Copied!
- resources
- views
- components
- button
- index.edge
Extending our example above, we can now have a button with a customized class like the below.
<form id="loginForm" action="{{ route('login')" method="POST" ></form> @button({ type: 'submit', form: 'loginForm', class: '!text-red-500' }) Login @endCopied!