Single component w/named slots for different content?

I have about ten (mostly single-field) forms that are displayed within collapsibles (“accordions”) on one page (this is sort of an admin-type view for editing properties). They all share a fair amount of code dealing with the collapsible itself, validation, the submission process, and so on. The structure of some forms with the same field type (e.g… text, textarea) are virtually identical. Others with checkbox fields have some similarities, but are not identical. And still others have a wholly unique structure. My current solution, utilizes a single component and several scoped slots for each field type. The slots utilize a prop (could be field type, or something else). The content for each name slot varies from short and simple (label, input, hint) to an entire form. And it seems to work.

Is this a reasonable way to use slots (it’s almost like multiple templates within a component), or should I be approaching this differently? Again, I’m doing this to avoid making multiple accordion components with duplicate template content (the accordion container), as well as computed properties and methods.

Please provide code related to your issue. Without it, it’s hard for us to help. You can refer to our guide on asking for help for more information. Thanks!

Sorry, here’s some sample pseudo-code. Hopefully the formatting isn’t too messed up.

The gist of this is that I am wrapping several short forms with varying content (some text fields, some fieldsets, etc.) within an accordion component. The form content varies widely, and I use a combo of slots and templates within the one type of Accordion component. The component file contains 1) for unique forms, a combination of named/scoped slots to call larger blade files that contain the necessary form content, sometimes passing data and functions; and 2) for more reusable form content, templates that contain the entire form structure; these are used by much shorter and simpler blade files.

My question is whether this is a reasonable way to reuse this component, or is it an abuse of slots and template tags, and there are much better ways to accomplish this.

// Accordion component

<template>

// Accordion stuff
//then several named slots based on prop values

// this one is used in a blade file that includes an entire form structure for two fields

        <template v-if="type === 'shell' && field === 'status'">
            <slot name="shell-status-body"></slot>
        </template>

// this is used in a similar way, but also passes data and a function

          <template v-if="type === 'shell' && field === 'sites'">
              <slot
              name="shell-site-body"
              :field="field"
              :v="v$"
              :open="open"
              :in-error-state="this.inErrorState"
              ></slot>
          </template>
          

  		 <template v-if="type === 'text'">
  		 // entire form structure for single text fields goes here
  		 </template>  



  		 <template v-else-if="type === 'fieldset'">
  		 // contains full form structure for a fieldset of checkboxes
  		 </template>         

</template>

// example blade file for text field

<wi-accordion
  field="project_name"
  type="text"
  csrf-token="{{ csrf_token()}}"
  group="1"
  @if (isset($is_review) && $is_review)
      :open-on-load="true"
  @endif
>
    <template v-slot:fieldhint="{field, v}">
        @{{ v.form[field].maxLength.$message }}.
    </template>

    <template v-slot:input="{field, v}">
        <input
          type="text"
          :id="`${field}_input`"
          :name="`${field}_input`"
          :ref="`${field}_input`"
          class="input project-edit-input"
          maxlength="150"
          required
          v-model="formStore.form.project_name"
          :aria-describedby="describe(field, v)"
          :aria-invalid="v.$error"
        >
    </template>


</wi-accordion>

// blade files for “shell” types contain entire form structure

Something I’m not connecting is why you need all these slots for an accordion. Perhaps the design of your accordion is much more complex than a standard collapsible block?

Commonly an accordion would have 1 or 2 slots. 1 for the heading/title and 1 for the content that gets shown/hidden.

So, to answer your original question based on the information I have, no, I don’t think this is a good pattern as it’s prone to bloat and breaks single responsibility for the component - an accordion should just be a block that can be toggled to show its content.

My approach would be to have a simple accordion component (as I described above) and then construct the relevant forms as components and slot that into the accordion as its content. The forms themselves are constructed of individual primitive input components that receive props/emit values from/to the parent form component which handles the validation and business logic.

Yes, I think I knew this and your suggestions are where I’ve been heading, at least in my mind. The reason for the multiple slots is not the accordion itself, but the variations in the form content. As you point out at the end of your response, I need to work in turning the forms into one or more components, which is still something of a challenge. So I was missing a key step by throwing all the slots into the accordion component. Thank you!