Currently Available: Need a skilled Software Developer for your next project?
Categories
Laravel

How to Add Custom Fields to Teams in Laravel Jetstream

If you're using Laravel Jetstream for team management, you might want to add custom fields to your teams. However, this isn't as straightforward as you might expect.

Jetstream doesn't publish its controllers to your application. Instead, it uses a pattern of "Actions" - classes that handle specific tasks like creating or updating teams. This approach gives you more flexibility but means you'll need to work with these Action classes to customize your teams.

I'll walk through how to add a website field to teams in Laravel Jetstream. You can use the same approach to add any custom fields you need, whether that's social media links, company information, or team preferences.

Overview

Let's break down what we need to do:

  1. Add the new field to the teams database table

    • We'll create a migration to add our website field to the existing teams table
  2. Update the Team model

    • We need to tell Laravel that our new field is "fillable" so it can be mass-assigned
  3. Modify the team creation form

    • We'll add the website field to the form that appears when someone creates a new team
    • This involves updating the Vue component that Jetstream provides
  4. Update the team settings form

    • Similar to the creation form, we need to add our field to the team settings page
    • This is where team owners can update their team's information
  5. Extend the team update logic

    • This is where we work with Jetstream's Action classes
    • We'll modify the update logic to handle our new field
    • We'll also add validation rules to make sure the website URL is valid

Step 1: Database Migration

Create a new migration to add the website field:

public function up(): void
{
    Schema::table('teams', function (Blueprint $table) {
        $table->string('website')->nullable();
    });
}

Step 2: Update Team Model

Add the new field to the $fillable array in your Team model:

protected $fillable = [
    'name',
    'website',
    'personal_team',
];

Step 3: Team Creation Form

Modify your CreateTeamForm.vue component to include the new field:

<div class="col-span-6 sm:col-span-4">
    <InputLabel for="website" value="Website" />
    <TextInput
        id="website"
        v-model="form.website"
        type="url"
        class="block w-full mt-1"
    />
    <InputError :message="form.errors.website" class="mt-2" />
</div>

Update the form data in the script section:

const form = useForm({
    name: '',
    website: '',
});

Step 4: Team Settings Form

Similarly, update your UpdateTeamNameForm.vue to include the new field:

<div class="col-span-6 sm:col-span-4">
    <InputLabel for="website" value="Website" />
    <TextInput
        id="website"
        v-model="form.website"
        type="url"
        class="mt-1 block w-full"
        :disabled="! permissions.canUpdateTeam"
    />
    <InputError :message="form.errors.website" class="mt-2" />
</div>

Initialize the form with the team's existing data:

const form = useForm({
    name: props.team.name,
    website: props.team.website || '',
});

Step 5: Update Action Class

Modify the UpdateTeamName action class in app/Actions/Jetstream/UpdateTeamName.php:

public function update(User $user, Team $team, array $input): void
{
    Gate::forUser($user)->authorize('update', $team);

    Validator::make($input, [
        'name' => ['required', 'string', 'max:255'],
        'website' => ['nullable', 'string', 'url', 'max:255'],
    ])->validateWithBag('updateTeamName');

    $team->forceFill([
        'name' => $input['name'],
        'website' => $input['website'],
    ])->save();
}

Understanding the Flow in Detail

When you submit the team update form, here's exactly what happens behind the scenes:

  1. The form sends a PUT request to the teams.update route
  2. The TeamController handles this request and calls:
    app(UpdatesTeamNames::class)->update($request->user(), $team, $request->all());
  3. Laravel's dependency injection resolves UpdatesTeamNames which is a contract (interface) defined in Jetstream
  4. Your application implements this contract through the UpdateTeamName class in app/Actions/Jetstream/UpdateTeamName.php
  5. The action class then:
    • Validates user permissions using Gates
    • Validates the input data
    • Saves the updated fields to the database

This architecture is intentional - Jetstream uses contracts and actions to allow you to customize the implementation without modifying vendor files. The empty UpdatesTeamNames interface in the vendor directory only defines the contract that your application must fulfill, while your local UpdateTeamName class provides the actual implementation.

Extending with Your Own Fields

The pattern shown here can be used to add any custom fields you need to your teams. Common examples include:

  • Company information (name, industry, size)
  • Contact details (email, phone, address)
  • Social media links
  • Team preferences or settings
  • Custom metadata

Just follow the same steps for each new field:

  1. Add it to the database
  2. Make it fillable in the model
  3. Add form inputs
  4. Update the validation rules
  5. Include it in the update logic
What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Subscribe to my newsletter

Get new posts when I publish them.

I respect your privacy. Unsubscribe at any time.

Leave a Reply

Your email address will not be published. Required fields are marked *