A modern, fully accessible emoji picker component for Blazor WebAssembly and Server applications. Features include live search, category organization, recent emoji tracking, WCAG 2.1 AA compliance (approaching AAA), full keyboard navigation, screen reader support, and programmatic dark mode with system preference detection.
$ dotnet add package BlazorEmoA modern, fully accessible emoji picker component for Blazor WebAssembly and Server applications.
dotnet add package BlazorEmo
The EmoPicker component works standalone without any service registration.
@page "/"
@using BlazorEmo.Components
@using BlazorEmo.Models
<button @onclick="() => isPickerOpen = true">
😀 Pick an Emoji
</button>
<EmoPicker IsOpen="@isPickerOpen"
OnEmojiSelected="HandleEmojiSelected"
OnClose="() => isPickerOpen = false"
UseCompleteDataset="true"
UseVirtualization="true"
DarkMode="@isDarkMode" />
<p>Selected: @selectedEmoji</p>
@code {
private bool isPickerOpen = false;
private bool isDarkMode = false;
private string selectedEmoji = "";
private void HandleEmojiSelected(Emo emoji)
{
selectedEmoji = emoji.Char;
isPickerOpen = false;
}
}
BlazorEmo supports both programmatic dark mode control and automatic system preference detection.
<EmoPicker DarkMode="@isDarkMode"
IsOpen="@isPickerOpen"
OnEmojiSelected="HandleEmojiSelected"
OnClose="() => isPickerOpen = false" />
<button @onclick="() => isDarkMode = !isDarkMode">
🌙 Toggle Dark Mode
</button>
The picker automatically detects and responds to the user's system color scheme preference via CSS @media (prefers-color-scheme: dark).
| Parameter | Type | Default | Description |
|---|---|---|---|
IsOpen | bool | false | Controls whether the picker is visible |
OnEmojiSelected | EventCallback<Emo> | Required | Fired when an emoji is selected |
OnClose | EventCallback | - | Fired when the picker should close |
OnOpened | EventCallback | - | Fired when the picker opens |
OnCategoryChanged | EventCallback<string> | - | Fired when category tab changes |
OnSearchChanged | EventCallback<string> | - | Fired when search text changes |
OnBeforeClose | Func<Task<bool>> | - | Async validation before close (return false to prevent) |
OnError | EventCallback<Exception> | - | Fired when an error occurs |
UseCompleteDataset | bool | false | Use full emoji dataset vs lite version |
UseVirtualization | bool | true | Enable virtualization for performance |
DarkMode | bool | false | Enable dark theme styling |
public class Emo
{
public string Code { get; set; } // "1f600"
public string Char { get; set; } // "😀"
public string Name { get; set; } // "Grinning Face"
public string[] Keywords { get; set; } // ["smile", "happy"]
public string? Category { get; set; } // "Smileys & Emotion"
}
| Key | Action |
|---|---|
Tab | Navigate between search, tabs, and emojis |
Shift+Tab | Navigate backwards |
Arrow Keys | Navigate between tabs and emoji grid |
Enter / Space | Select focused emoji or activate tab |
Escape | Close picker |
Home / End | Jump to first/last item |
Track user interactions with the emoji picker:
<EmoPicker IsOpen="@isPickerOpen"
OnEmojiSelected="HandleEmojiSelected"
OnClose="CloseHandler"
OnOpened="() => pickerOpenCount++"
OnCategoryChanged="category => currentCategory = category"
OnSearchChanged="query => currentSearch = query" />
@code {
private int pickerOpenCount = 0;
private string currentCategory = "";
private string currentSearch = "";
private void HandleEmojiSelected(Emo emoji)
{
Console.WriteLine($"Selected: {emoji.Name}");
// Analytics tracking, logging, etc.
}
}
The picker uses virtualization by default to efficiently render large emoji datasets. Only visible emojis are rendered in the DOM.
<!-- Recommended for complete dataset -->
<EmoPicker UseCompleteDataset="true"
UseVirtualization="true" />
<!-- For smaller datasets, virtualization can be disabled -->
<EmoPicker UseCompleteDataset="false"
UseVirtualization="false" />
Recently used emojis are stored in browser localStorage (max 30) and automatically displayed in the "Recent" tab for quick access.
dotnet build
dotnet test
cd BlazorEmo.Demo
dotnet run
Then navigate to the displayed URL (typically https://localhost:5001) to see the interactive demo.
Future enhancements being considered:
This project is licensed under the MIT License.
For issues and questions, please visit:
Made with ❤️ by LoneWorx LLC