It looks like you're on the right track with using the afterStateUpdated callback to update the options for the CheckboxList. However, the way you're trying to update the options for contact_ids is not correct. You should use the get method on the CheckboxList to retrieve the component and then call the options method to update its options.
Here's how you can modify your Select::make('client_id') to update the CheckboxList options dynamically:
Select::make('client_id')
->relationship('client', 'name')
->searchable(['name'])
->preload()
->required()
->reactive()
->createOptionForm(Client::getForm())
->afterStateUpdated(function (Closure $set, $state, $livewire) {
// Clear the selected contacts when the client changes
$set('contact_ids', []);
// Retrieve contacts based on the selected client
$contacts = Contact::where('client_id', $state)->pluck('name', 'id')->toArray();
// Update the options for the CheckboxList
$livewire->form->get('contact_ids')->options($contacts);
}),
Make sure to replace 'name' with the actual attribute of the Contact model you want to display in the checkbox list.
Also, note that I've added a third parameter $livewire to the callback function. This is the instance of the Livewire component, which allows you to access the form and its fields.
The pluck method is used to get a collection of name and id pairs from the Contact model, which are then converted to an array with toArray() and passed to the options method of the CheckboxList.
Make sure that the name attribute in the pluck method call corresponds to the attribute you want to display for each contact in the checkbox list. If you want to display the full name or a combination of first and last names, you might need to adjust your query or use a different method to retrieve the desired display value.