Playing Next Lesson In
seconds

EdgeJS Components #3.0

Creating Our Base Button

In This Lesson

We'll create our base button component which al our other button styles will derive from. It'll be in charge of building our classes, adding interactivity, and more.

Created by
@tomgobich
Published

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.edge
Copied!

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>

@end
Copied!
  • 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
@end
Copied!

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
@end
Copied!

Join the Discussion 0 comments

Create a free account to join in on the discussion
robot comment bubble

Be the first to comment!