# Clients

*Bridge server-side C# code with client-side React components for seamless browser interactions and client-side operations.*

## Overview

The `IClientProvider` interface is the main entry point for client-side interactions. It's available through dependency injection using the [UseService](../../03_Hooks/02_Core/11_UseService.md) hook:

```csharp
var client = UseService<IClientProvider>();
```

## Common Use Cases

You can show [toasts](./17_Alerts.md):

```csharp
// Simple toast
client.Toast("Operation successful!");

// Toast with title
client.Toast("Data saved", "Success");
```

You can [navigate](./09_Navigation.md) to different pages within the app:

```csharp
// Navigate to different pages within the app
client.Navigate("/dashboard");

// Redirect to external site (replaces current page)
client.Redirect("https://example.com");

// Open URL in new tab (keeps current page open)
client.OpenUrl("https://github.com");
client.OpenUrl(new Uri("https://stackoverflow.com"));
```

You can download and [upload](../../02_Widgets/04_Inputs/10_FileInput.md) files:

```csharp
// Download CSV data
var csvData = Encoding.UTF8.GetBytes("Name,Age\nJohn,30\nJane,25");
client.DownloadFile("users.csv", csvData, "text/csv");

// Download with progress tracking
var progress = UseState(0.0);
client.DownloadFile("large-file.zip", fileData, onProgress: p => progress.Value = p);
```

```csharp
// Handle single file upload
client.UploadFiles(async files => {
    var file = files.FirstOrDefault();
    if (file != null)
    {
        var content = await file.GetContentAsync();
        await ProcessFileAsync(file.FileName, content);
        client.Toast($"Uploaded {file.FileName}");
    }
});
```

You can copy text to the clipboard:

```csharp
// Copy text to clipboard
client.CopyToClipboard("Copied to clipboard!");
client.Toast("Text copied!");
```

You can set the [theme mode](./12_Theming.md) and apply custom CSS:

```csharp
// Set theme mode
client.SetThemeMode(ThemeMode.Dark);

// Apply custom CSS
var customCss = @"
:root {
    --primary: #ff6b6b;
    --secondary: #4ecdc4;
}";
client.ApplyTheme(customCss);
```

## Best Practices

1. **Dependency Injection**: Always use `UseService<IClientProvider>()` to get the client instance.
2. **Error Handling**: Wrap client operations in try-catch blocks when appropriate.
3. **Async Operations**: Use async/await for operations that might take time.
4. **State Management**: Use clients in combination with [state management](../../03_Hooks/02_Core/03_UseState.md) for reactive updates.

## UI Refresh & State Management

Ivy automatically handles UI refreshes in most cases. You typically **don't need** to manually refresh the UI:

- **[Form](./08_Forms.md) submissions**: When forms are submitted successfully, the UI automatically updates
- **State changes**: When [state](../../03_Hooks/02_Core/03_UseState.md) values change, the UI automatically re-renders
- **Sheet dismissal**: [Sheets](../../02_Widgets/07_Advanced/02_Sheet.md) are automatically closed by the framework when forms are submitted successfully
- **Navigation**: Page [navigation](./09_Navigation.md) automatically refreshes the UI

**Do this instead** - Let the framework handle it:

```csharp
// Just update state, UI refreshes automatically
var isOpen = UseState(false);
var formData = UseState("");

// When form submits successfully, sheet closes automatically
if (formSubmitted.Value)
{
    formSubmitted.Value = false;
    isOpen.Value = false; // This triggers UI update
    client.Toast("Form saved successfully!");
}
```

## Examples


### Form Submission with Toast Feedback

```csharp
public class FormSubmissionApp : ViewBase
{
    public override object? Build()
    {
        var client = UseService<IClientProvider>();
        var nameState = UseState("");
        var submitTrigger = UseState(false);
        
        if (submitTrigger.Value)
        {
            submitTrigger.Value = false;
            var name = nameState.Value;
            if (string.IsNullOrEmpty(name))
            {
                client.Toast("Please enter a name", "Validation Error");
            }
            else
            {
                client.Toast($"Hello, {name}! Form submitted successfully.");
            }
        }
        
        return Layout.Vertical(
            new TextInput(nameState.Value, e => nameState.Value = e.Value) { Placeholder = "Your name" },
            new Button("Submit Form", _ => submitTrigger.Value = true)
        );
    }
}
```




### File Operations Simulation

```csharp
public class FileOperationsApp : ViewBase
{
    public override object? Build()
    {
        var client = UseService<IClientProvider>();
        var downloadTrigger = UseState(false);
        var uploadTrigger = UseState(false);
        var downloadComplete = UseState(false);
        var uploadComplete = UseState(false);
        
        if (downloadTrigger.Value)
        {
            downloadTrigger.Value = false;
            downloadComplete.Value = false;
            client.Toast("Downloading file...", "Download Started");
            
            // Simulate download completion after 2 seconds
            Task.Run(async () => {
                await Task.Delay(2000);
                downloadComplete.Value = true;
            });
        }
        
        if (uploadTrigger.Value)
        {
            uploadTrigger.Value = false;
            uploadComplete.Value = false;
            client.Toast("Uploading files...", "Upload Started");
            
            // Simulate upload completion after 3 seconds
            Task.Run(async () => {
                await Task.Delay(3000);
                uploadComplete.Value = true;
            });
        }
        
        // Show completion messages when state changes
        if (downloadComplete.Value)
        {
            downloadComplete.Value = false;
            client.Toast("File downloaded successfully!");
        }
        
        if (uploadComplete.Value)
        {
            uploadComplete.Value = false;
            client.Toast("Files uploaded successfully!");
        }
        
        return Layout.Vertical(
            new Button("Simulate File Download", _ => downloadTrigger.Value = true),
            new Button("Simulate File Upload", _ => uploadTrigger.Value = true)
        );
    }
}
```




### Navigation and URL Management

```csharp
public class ClientNavigationApp : ViewBase
{
    public override object? Build()
    {
        var client = UseService<IClientProvider>();
        var copyTrigger = UseState(false);
        var openTabsTrigger = UseState(false);
        
        if (copyTrigger.Value)
        {
            copyTrigger.Value = false;
            var appDescriptor = UseService<AppDescriptor>();
            var info = $"Current app: {appDescriptor.Title}";
            client.CopyToClipboard(info);
            client.Toast("Page info copied to clipboard!");
        }
        
        if (openTabsTrigger.Value)
        {
            openTabsTrigger.Value = false;
            client.OpenUrl("https://google.com");
            client.OpenUrl("https://github.com");
            client.Toast("Opened multiple tabs", "Navigation");
        }
        
        return Layout.Vertical(
            new Button("Copy Current Page Info", _ => copyTrigger.Value = true),
            new Button("Open Multiple Tabs", _ => openTabsTrigger.Value = true)
        );
    }
}
```



## See Also

- [Forms](./08_Forms.md)
- [State Management](../../03_Hooks/02_Core/03_UseState.md)
- [Effects](../../03_Hooks/02_Core/04_UseEffect.md)
- [Alerts & Notifications](./17_Alerts.md)