Customization
This guide covers how to customize Django RemixIcon to fit your project’s needs.
Widget Customization
Custom CSS Styling
You can override the default widget styles by including custom CSS:
/* Custom styles for the icon widget */
.remix-icon-widget {
max-width: 500px; /* Increase widget width */
}
.icon-search-input {
padding: 12px 16px; /* Larger padding */
border-radius: 8px; /* Rounded corners */
border: 2px solid #e1e5e9; /* Thicker border */
font-size: 16px; /* Larger font */
}
.icon-search-input:focus {
border-color: #007cba;
box-shadow: 0 0 0 3px rgba(0, 124, 186, 0.1);
}
/* Customize search results */
.icon-search-results {
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
max-height: 300px; /* Increase dropdown height */
}
.icon-search-result {
padding: 12px 16px; /* Match input padding */
}
.icon-search-result:hover {
background-color: #f8f9fa;
}
.icon-search-result.selected {
background-color: #007cba;
}
/* Customize icon preview */
.icon-preview {
border-radius: 8px;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
}
.icon-preview i {
font-size: 24px; /* Larger preview icon */
color: #007cba;
}
Dark Theme Support
Add dark theme styles for better integration:
/* Dark theme styles */
@media (prefers-color-scheme: dark) {
.remix-icon-widget {
--bg-color: #2d3748;
--border-color: #4a5568;
--text-color: #f7fafc;
--hover-bg: #4a5568;
--focus-color: #63b3ed;
}
.icon-search-input {
background-color: var(--bg-color);
border-color: var(--border-color);
color: var(--text-color);
}
.icon-search-input:focus {
border-color: var(--focus-color);
box-shadow: 0 0 0 3px rgba(99, 179, 237, 0.2);
}
.icon-search-results {
background-color: var(--bg-color);
border-color: var(--border-color);
}
.icon-search-result:hover {
background-color: var(--hover-bg);
}
.icon-preview {
background-color: var(--bg-color);
border-color: var(--border-color);
color: var(--text-color);
}
}
Custom Widget Implementation
You can create your own widget based on the provided ones:
# widgets.py
from django_remix_icon.widgets import IconSelectWidget
class CustomIconWidget(IconSelectWidget):
template_name = 'myapp/custom_icon_widget.html'
class Media:
css = {
'all': (
'django_remix_icon/css/icon_select.css',
'myapp/css/custom_icon_widget.css',
)
}
js = (
'django_remix_icon/js/icon_select.js',
'myapp/js/custom_icon_widget.js',
)
def __init__(self, attrs=None):
default_attrs = {'class': 'my-custom-icon-widget'}
if attrs:
default_attrs.update(attrs)
super().__init__(default_attrs)
# forms.py
from django import forms
from .widgets import CustomIconWidget
class MyForm(forms.Form):
icon = forms.CharField(widget=CustomIconWidget())
Template Customization
Custom Icon Rendering
Override the default template tags behavior by creating custom template tags:
# templatetags/my_icon_tags.py
from django import template
from django.utils.safestring import mark_safe
from django_remix_icon.templatetags.remix_icon_tags import remix_icon as base_remix_icon
register = template.Library()
@register.simple_tag
def my_remix_icon(icon_name, **kwargs):
"""Custom icon rendering with additional features"""
# Add default CSS class
css_classes = kwargs.get('class', '').split()
css_classes.append('my-icon')
kwargs['class'] = ' '.join(css_classes)
# Add data attributes for JavaScript
kwargs['data-icon'] = icon_name
return base_remix_icon(icon_name, **kwargs)
Custom Inclusion Templates
Override the included templates:
<!-- templates/django_remix_icon/icon_with_text.html -->
{% load remix_icon_tags %}
<div class="icon-text-wrapper"{% for key, value in attrs.items %} {{ key }}="{{ value }}"{% endfor %}>
{% if is_valid_icon %}
<span class="icon-container">
{% remix_icon icon_name %}
</span>
{% endif %}
{% if text %}
<span class="text-container">{{ text }}</span>
{% endif %}
</div>
Field Customization
Custom Field with Additional Features
Extend the IconField to add custom functionality:
# fields.py
from django_remix_icon.fields import IconField as BaseIconField
from django.core.exceptions import ValidationError
class CategoryIconField(BaseIconField):
"""IconField that only allows category-related icons"""
def __init__(self, *args, **kwargs):
self.allowed_categories = kwargs.pop('allowed_categories', ['user', 'home', 'business'])
super().__init__(*args, **kwargs)
def validate(self, value, model_instance):
super().validate(value, model_instance)
if value:
# Check if icon belongs to allowed categories
if not any(cat in value.lower() for cat in self.allowed_categories):
raise ValidationError(
f"Icon must be from categories: {', '.join(self.allowed_categories)}"
)
# Usage in models
class Category(models.Model):
name = models.CharField(max_length=100)
icon = CategoryIconField(allowed_categories=['folder', 'tag', 'bookmark'])
Custom Form Field
Create a custom form field with additional validation:
# forms.py
from django import forms
from django_remix_icon.fields import IconFormField as BaseIconFormField
from django_remix_icon.remix_icons import get_icon_names
class FilteredIconFormField(BaseIconFormField):
def __init__(self, icon_filter=None, *args, **kwargs):
self.icon_filter = icon_filter or []
super().__init__(*args, **kwargs)
if self.icon_filter:
# Filter choices based on the filter
all_icons = get_icon_names()
filtered_icons = [
icon for icon in all_icons
if any(f in icon.lower() for f in self.icon_filter)
]
self.choices = [(icon, icon.replace('ri-', '').replace('-', ' ').title())
for icon in filtered_icons]
Admin Customization
Custom Admin Widget Configuration
Customize how the widget appears in Django admin:
# admin.py
from django.contrib import admin
from django import forms
from django_remix_icon.widgets import IconSelectWidget
class CustomIconWidget(IconSelectWidget):
def __init__(self, attrs=None):
default_attrs = {
'class': 'custom-admin-icon-widget',
'data-placeholder': 'Choose an icon...',
}
if attrs:
default_attrs.update(attrs)
super().__init__(default_attrs)
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = '__all__'
widgets = {
'icon': CustomIconWidget(),
}
@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
form = MyModelForm
Inline Customization
Customize how the widget appears in inline admin forms:
class MyInlineForm(forms.ModelForm):
class Meta:
model = MyInlineModel
fields = '__all__'
widgets = {
'icon': IconSelectWidget(attrs={
'class': 'inline-icon-widget',
'style': 'width: 200px;'
}),
}
class MyInline(admin.TabularInline):
model = MyInlineModel
form = MyInlineForm
extra = 1
JavaScript Customization
Extending Widget JavaScript
Add custom JavaScript functionality to the widget:
// static/js/custom_icon_widget.js
(function() {
'use strict';
// Wait for the base widget to initialize
document.addEventListener('DOMContentLoaded', function() {
// Extend existing functionality
if (window.DjangoRemixIcon) {
const originalInit = window.DjangoRemixIcon.initializeWidget;
window.DjangoRemixIcon.initializeWidget = function(widget) {
// Call original initialization
originalInit(widget);
// Add custom functionality
addCustomFeatures(widget);
};
}
});
function addCustomFeatures(widget) {
const searchInput = widget.querySelector('.icon-search-input');
if (searchInput) {
// Add custom keyboard shortcuts
searchInput.addEventListener('keydown', function(e) {
if (e.ctrlKey && e.key === 'k') {
e.preventDefault();
this.focus();
this.select();
}
});
// Add custom search behavior
searchInput.addEventListener('input', debounce(function() {
// Custom search logic
console.log('Custom search for:', this.value);
}, 300));
}
}
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
})();
Custom Icon Categories
Create a system for categorizing icons:
// static/js/icon_categories.js
const ICON_CATEGORIES = {
'navigation': [
'ri-home-line', 'ri-arrow-left-line', 'ri-arrow-right-line',
'ri-menu-line', 'ri-more-line'
],
'actions': [
'ri-add-line', 'ri-edit-line', 'ri-delete-bin-line',
'ri-save-line', 'ri-download-line'
],
'communication': [
'ri-mail-line', 'ri-phone-line', 'ri-message-line',
'ri-chat-1-line'
],
'media': [
'ri-image-line', 'ri-video-line', 'ri-music-line',
'ri-camera-line'
]
};
function getIconsByCategory(category) {
return ICON_CATEGORIES[category] || [];
}
function getCategoryForIcon(icon) {
for (const [category, icons] of Object.entries(ICON_CATEGORIES)) {
if (icons.includes(icon)) {
return category;
}
}
return 'other';
}
URL Configuration Customization
Custom URL Patterns
Customize the URL patterns for the package views:
# urls.py
from django.urls import path
from django_remix_icon import views
# Custom URL configuration
app_name = 'custom_remix_icon'
urlpatterns = [
path('icon-search/', views.IconSearchView.as_view(), name='icon_search'),
path('icon-list/', views.icon_list_view, name='icon_list'),
# Add custom endpoints
path('icon-categories/', custom_category_view, name='icon_categories'),
]
# In your main urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('custom-icons/', include('myapp.urls')),
]
Performance Optimization
Caching Icon Data
Implement custom caching for better performance:
# utils.py
from django.core.cache import cache
from django_remix_icon.remix_icons import get_icon_names
def get_cached_icons():
"""Get icons with caching"""
icons = cache.get('remix_icons_list')
if icons is None:
icons = get_icon_names()
cache.set('remix_icons_list', icons, 3600) # Cache for 1 hour
return icons
Custom Search Implementation
Implement more sophisticated search:
# views.py
from django.http import JsonResponse
from django.views.generic import View
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
import re
@method_decorator(csrf_exempt, name='dispatch')
class AdvancedIconSearchView(View):
def get(self, request):
query = request.GET.get('q', '').lower().strip()
limit = int(request.GET.get('limit', 20))
if not query:
return JsonResponse({'results': [], 'total': 0})
icons = get_cached_icons()
# Advanced search with scoring
results = []
for icon in icons:
score = self.calculate_relevance_score(icon, query)
if score > 0:
results.append({
'icon': icon,
'score': score,
'value': icon,
'label': icon.replace('ri-', '').replace('-', ' ').title()
})
# Sort by relevance score
results.sort(key=lambda x: x['score'], reverse=True)
results = results[:limit]
return JsonResponse({
'results': [r for r in results],
'total': len(results)
})
def calculate_relevance_score(self, icon, query):
icon_lower = icon.lower()
# Exact match
if query in icon_lower:
if icon_lower.startswith(query):
return 100 # Starts with query
elif query in icon_lower.replace('ri-', ''):
return 80 # Contains query in main part
else:
return 60 # Contains query anywhere
# Fuzzy matching
query_words = query.split()
icon_words = icon_lower.replace('ri-', '').split('-')
matches = sum(1 for qw in query_words for iw in icon_words if qw in iw)
if matches > 0:
return 40 + (matches * 10)
return 0
Integration Examples
Bootstrap Integration
<!-- Bootstrap-styled icon buttons -->
<div class="btn-group" role="group">
<button type="button" class="btn btn-outline-primary">
{% remix_icon 'ri-home-line' %} Home
</button>
<button type="button" class="btn btn-outline-primary">
{% remix_icon 'ri-user-line' %} Profile
</button>
<button type="button" class="btn btn-outline-primary">
{% remix_icon 'ri-settings-line' %} Settings
</button>
</div>
Tailwind CSS Integration
<!-- Tailwind-styled icon navigation -->
<nav class="flex space-x-4">
<a href="#" class="flex items-center space-x-2 px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
{% remix_icon 'ri-dashboard-line' class='w-5 h-5' %}
<span>Dashboard</span>
</a>
<a href="#" class="flex items-center space-x-2 px-3 py-2 rounded-md text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
{% remix_icon 'ri-team-line' class='w-5 h-5' %}
<span>Team</span>
</a>
</nav>
Next Steps
Fields API Reference - Complete API reference
Widgets API Reference - Widget API documentation
Template Tags API Reference - Template tags API reference