> ## Documentation Index
> Fetch the complete documentation index at: https://filamentphp.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Advanced

export const EditOnGitHub = ({version, path}) => {
  const url = `https://github.com/filamentphp/filament/edit/${version}/${path}`;
  return <div className="not-prose mt-16">
      <a href={url} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-2 text-sm text-gray-500 transition hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" className="h-4 w-4">
          <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" />
        </svg>
        Edit this page on GitHub
      </a>
    </div>;
};

export const Footer = () => {
  const sponsorsByTier = JSON.parse(`{
  "agency_partner": [
    {
      "name": "Kirschbaum",
      "url": "https://kirschbaumdevelopment.com/solutions/filament-development",
      "filename": "kirschbaum.svg"
    }
  ],
  "gold": [
    {
      "name": "Agiledrop",
      "url": "https://www.agiledrop.com/laravel?utm_source=filament",
      "filename": "agiledrop.svg"
    },
    {
      "name": "Baiz.ai",
      "url": "https://baiz.ai",
      "filename": "baiz-ai.svg"
    },
    {
      "name": "CMS Max",
      "url": "https://cmsmax.com?ref=filamentphp.com",
      "filename": "cms-max.svg"
    },
    {
      "name": "Mailtrap",
      "url": "https://mailtrap.io/email-sending?utm_source=community&utm_medium=referral&utm_campaign=filament",
      "filename": "mailtrap.svg"
    },
    {
      "name": "SerpApi",
      "url": "https://serpapi.com/?utm_source=filamentphp",
      "filename": "serpapi.svg"
    }
  ]
}`);
  function shuffleArray(items) {
    const result = [...items];
    for (let index = result.length - 1; index > 0; index--) {
      const randomIndex = Math.floor(Math.random() * (index + 1));
      [result[index], result[randomIndex]] = [result[randomIndex], result[index]];
    }
    return result;
  }
  const sponsors = Object.entries(sponsorsByTier).flatMap(([, sponsors]) => shuffleArray(sponsors));
  return <div className="mt-16 flex flex-col gap-4">
      <h2 className="text-center text-2xl font-medium text-gray-800 dark:text-gray-200">
        Sponsored by
      </h2>

      <div className="not-prose flex flex-wrap items-center justify-center gap-5">
        {sponsors.map(sponsor => <a key={sponsor.name} className="footer-sponsor-card" href={sponsor.url} target="_blank" title={sponsor.name}>
            <img src={`/docs/images/sponsors/footer/${sponsor.filename}`} alt={sponsor.name} noZoom />
            <span className="line-pattern-overlay line-pattern-80" />
          </a>)}

        <a href="https://github.com/sponsors/danharrin" target="_blank" className="footer-sponsor-cta">
          <span className="sponsor-cta-content">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M5 12h14" />
              <path d="M12 5v14" />
            </svg>
            <span>Your logo here</span>
          </span>
          <span className="line-pattern-overlay line-pattern-60" />
        </a>
      </div>
    </div>;
};

<Warning>
  You are currently viewing the documentation for Filament 2.x, which is a previous version of Filament.

  Looking for the current stable version? Visit the [5.x documentation](/5.x/forms).
</Warning>

## Using closure customization

All configuration methods for [fields](./fields) and [layout components](./layout) accept closures as parameters instead of hardcoded values:

```php theme={"theme":"gruvbox-dark-hard"}
use App\Models\User;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;

DatePicker::make('date_of_birth')
    ->displayFormat(function () {
        if (auth()->user()->country_id === 'us') {
            return 'm/d/Y'
        } else {
            return 'd/m/Y'
        }
    })

Select::make('userId')
    ->options(function () {
        return User::all()->pluck('name', 'id');
    })

TextInput::make('middle_name')
    ->required(function () {
        return auth()->user()->hasMiddleName();
    })
```

This alone unlocks many customization possibilities.

The package is also able to inject many utilities to use inside these closures, as parameters.

If you wish to access the current state (value) of the component, define a `$state` parameter:

```php theme={"theme":"gruvbox-dark-hard"}
function ($state) {
    // ...
}
```

If you wish to access the current component instance, define a `$component` parameter:

```php theme={"theme":"gruvbox-dark-hard"}
use Filament\Forms\Components\Component;

function (Component $component) {
    // ...
}
```

If you wish to access the current Livewire component instance, define a `$livewire` parameter:

```php theme={"theme":"gruvbox-dark-hard"}
use Livewire\Component as Livewire;

function (Livewire $livewire) {
    // ...
}
```

If you have defined a form or component Eloquent model instance, define a `$record` parameter:

```php theme={"theme":"gruvbox-dark-hard"}
use Illuminate\Database\Eloquent\Model;

function (?Model $record) {
    // ...
}
```

You may also retrieve the value of another field from within a callback, using a closure `$get` parameter:

```php theme={"theme":"gruvbox-dark-hard"}
use Closure;

function (Closure $get) {
    $email = $get('email'); // Store the value of the `email` field in the `$email` variable.
    //...
}
```

In a similar way to `$get`, you may also set the value of another field from within a callback, using a closure `$set` parameter:

```php theme={"theme":"gruvbox-dark-hard"}
use Closure;

function (Closure $set) {
    $set('title', 'Blog Post'); // Set the `title` field to `Blog Post`.
    //...
}
```

If you're writing a form for an admin panel resource or relation manager, and you wish to check if a form is `create`, `edit` or `view`, use the `$context` parameter:

```php theme={"theme":"gruvbox-dark-hard"}
function (string $context) {
    // ...
}
```

> Outside of the admin panel, you can set a form's context by defining a `getFormContext()` method on your Livewire component.

Callbacks are evaluated using Laravel's `app()->call()` under the hood, so you are able to combine multiple parameters in any order:

```php theme={"theme":"gruvbox-dark-hard"}
use Closure;
use Livewire\Component as Livewire;

function (Livewire $livewire, Closure $get, Closure $set) {
    // ...
}
```

### Reloading the form when a field is updated

By default, forms are only reloaded when they are validated or submitted. You may allow a form to be reloaded when a field is changed, by using the `reactive()` method on that field:

```php theme={"theme":"gruvbox-dark-hard"}
use Filament\Forms\Components\TextInput;

TextInput::make('title')->reactive()
```

A great example to give a use case for this is when you wish to generate a slug from a title field automatically:

<iframe width="560" height="315" src="https://www.youtube.com/embed/GNsk5z7-PEs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen />

## Dependant fields / components

You may use the techniques described in the [closure customization section](#using-closure-customization) to build completely dependent fields and components, with full control over customization based on the values of other fields in your form.

For example, you can build dependant [select](./fields#select) inputs:

<iframe width="560" height="315" src="https://www.youtube.com/embed/W_eNyimRi3w" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen />

Sometimes, you may wish to conditionally hide any form component based on the value of a field. You may do this with a `hidden()` method:

```php theme={"theme":"gruvbox-dark-hard"}
use Closure;
use Filament\Forms\Components\TextInput;

TextInput::make('newPassword')
    ->password()
    ->reactive()

TextInput::make('newPasswordConfirmation')
    ->password()
    ->hidden(fn (Closure $get) => $get('newPassword') === null)
```

The field/s you're depending on should be `reactive()`, to ensure the Livewire component is reloaded when they are updated.

## Field lifecycle

### Hydration

Hydration is the process which fill fields with data. It runs when you call the [form's `fill()` method](./getting-started#filling-forms-with-data). You may customize what happens after a field is hydrated using the `afterStateHydrated()`.

In this example, the `name` field will always be hydrated with the correctly capitalized name:

```php theme={"theme":"gruvbox-dark-hard"}
use Closure;
use Filament\Forms\Components\TextInput;

TextInput::make('name')
    ->afterStateHydrated(function (TextInput $component, $state) {
        $component->state(ucwords($state));
    })
```

### Updates

You may use the `afterStateUpdated()` method to customize what happens after a field is updated.

In this example, the `slug` field is updated with the slug version of the `title` field automatically:

```php theme={"theme":"gruvbox-dark-hard"}
use Closure;
use Filament\Forms\Components\TextInput;
use Illuminate\Support\Str;

TextInput::make('title')
    ->reactive()
    ->afterStateUpdated(function (Closure $set, $state) {
        $set('slug', Str::slug($state));
    })
TextInput::make('slug')
```

### Dehydration

Dehydration is the process which gets data from fields, and transforms it. It runs when you call the [form's `getState()` method](./getting-started#getting-data-from-forms). You may customize how the state is dehydrated from the form by returning the transformed state from the `dehydrateStateUsing()` callback.

In this example, the `name` field will always be dehydrated with the correctly capitalized name:

```php theme={"theme":"gruvbox-dark-hard"}
use Filament\Forms\Components\TextInput;

TextInput::make('name')->dehydrateStateUsing(fn ($state) => ucwords($state))
```

You may also prevent the field from being dehydrated altogether by passing `false` to `dehydrated()`.

In this example, the `passwordConfirmation` field will not be present in the array returned from `getData()`:

```php theme={"theme":"gruvbox-dark-hard"}
use Filament\Forms\Components\TextInput;

TextInput::make('passwordConfirmation')
    ->password()
    ->dehydrated(false)
```

## Using form events

Forms can dispatch and listen to events, which allow the frontend and backend to communicate.

These events can be dispatched in a component view, and then listened to by a component's class.

### Dispatching events

To dispatch a form event, call the `dispatchFormEvent()` Livewire method with the event name:

```blade theme={"theme":"gruvbox-dark-hard"}
<button wire:click="dispatchFormEvent('save')">
    Save
</button>
```

Usually, you will want to dispatch events for a specific component class. In this case, you should prefix the event name with the component name, and pass the component's state path as a second parameter:

```blade theme={"theme":"gruvbox-dark-hard"}
<button wire:click="dispatchFormEvent('repeater::createItem', '{{ $getStatePath() }}')">
    Add item
</button>
```

You may also pass other parameters to the event:

```blade theme={"theme":"gruvbox-dark-hard"}
<button wire:click="dispatchFormEvent('repeater::deleteItem', '{{ $getStatePath() }}', '{{ $uuid }}')">
    Delete item
</button>
```

### Listening to events

You may register listeners for form events by calling the `registerListeners()` method when your component is `setUp()`:

```php theme={"theme":"gruvbox-dark-hard"}
use Filament\Forms\Components\Component;

protected function setUp(): void
{
    parent::setUp();

    $this->registerListeners([
        'save' => [
            function (Component $component): void {
                // ...
            },
        ],
    ]);
}
```

If your event is component-specific, you'll want to ensure that the component is not disabled, and that the component's state path matches the event's second parameter:

```php theme={"theme":"gruvbox-dark-hard"}
use Filament\Forms\Components\Component;

protected function setUp(): void
{
    parent::setUp();

    $this->registerListeners([
        'repeater::createItem' => [
            function (Component $component, string $statePath): void {
                if ($component->isDisabled()) {
                    return;
                }

                if ($statePath !== $component->getStatePath()) {
                    return;
                }

                // ...
            },
        ],
    ]);
}
```

Additionally, you may receive other parameters from the event:

```php theme={"theme":"gruvbox-dark-hard"}
use Filament\Forms\Components\Component;

protected function setUp(): void
{
    parent::setUp();

    $this->registerListeners([
        'repeater::deleteItem' => [
            function (Component $component, string $statePath, string $uuidToDelete): void {
                if ($component->isDisabled()) {
                    return;
                }

                if ($statePath !== $component->getStatePath()) {
                    return;
                }

                // Delete item with UUID `$uuidToDelete`
            },
        ],
    ]);
}
```

<EditOnGitHub version="2.x" path="packages/forms/docs/06-advanced.md" />

<Footer />
