Back to Course |
[Mini-course] Filament: Visual Customizations

Dashboard Widgets Customizations

In this lesson, we will look at styling stats and chart widgets on the dashboard.

We will use the open-source code from the Filament official demo project, which can be found on GitHub.

To customize the dashboard, you need to learn two things:

  • Creating Filament custom themes
  • CSS and Tailwind Classes

DISCLAIMER: This lesson isn't about CSS or Tailwind. We have a separate course Tailwind CSS for Laravel Developers.


Creating a Custom Theme

To style the Filament panel or use other Tailwind styles that Filament isn't using, first, you must create a custom theme. A custom theme is created using an Artisan command.

php artisan make:filament-theme

After creating a theme, you must follow the instructions from the command output to complete the setup.

vite.config.js:

import { defineConfig } from 'vite'
import laravel, { refreshPaths } from 'laravel-vite-plugin'
 
export default defineConfig({
plugins: [
laravel.default({
input: ['resources/css/app.css', 'resources/css/filament/admin/theme.css', 'resources/js/app.js'],
refresh: [
...refreshPaths,
'app/Filament/**',
'app/Forms/Components/**',
'app/Livewire/**',
'app/Infolists/Components/**',
'app/Providers/Filament/**',
'app/Tables/Columns/**',
],
}),
],
})

app/Providers/Filament/AdminPanelProvider.php:

class AdminPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
// ...
->viteTheme('resources/css/filament/admin/theme.css');
}
}

Now that the theme is registered, let's try changing the background color to see if everything works. First, we must find which CSS class hook to use.


Filament Hook Classes

Filament has many hook CSS classes. All hook classes are prefixed with `fi-', which is a great way to identify them, and they are usually at the start of the class list.

Filament recommends avoiding hacking around if you don't find a hook class. Instead, you should make a pull request to add the hook class.

These are a few common abbreviations Filament uses for hook classes to keep them short and readable:

  • fi is short for "Filament"
  • fi-ac is used to represent classes used in the Actions package
  • fi-fo is used to represent classes used in the Form Builder package
  • fi-in is used to represent classes used in the Infolist Builder package
  • fi-no is used to represent classes used in the Notifications package
  • fi-ta is used to represent classes used in the Table Builder package
  • fi-wi is used to represent classes used in the Widgets package
  • btn is short for "button"
  • col is short for "column"
  • ctn is short for "container"
  • wrp is short for "wrapper"

It is not recommended to publish Filament's Views to customize them. Published Views could lead to breaking changes with future updates.

The easiest way to find class hooks is by using your browser's developer tools and inspecting the element. For example, after inspecting a stats widget, we can see these Filament CSS hook classes:


Change Background Color

After inspecting the content, we see the fi-main-ctn hook class.

Now, let's use this CSS class and change the background color. For the color, you can choose any color from the Tailwind color palette.

resources/css/filament/admin/theme.css:

@import '/vendor/filament/filament/resources/css/theme.css';
 
@config 'tailwind.config.js';
 
.fi-main-ctn {
@apply bg-slate-100;
}

After making any style changes, you need to recompile CSS using npm run build or while making changes with npm run dev. After recompiling, we can see the background has changed. That's good; now we can style other elements.


Styling Stats Widget

Now, let's try to add some styles to the stats widget. We know how to check what CSS classes to use, and earlier in this lesson, we inspected the names of these classes.

Let's add some shadow to the card itself.

resources/css/filament/admin/theme.css:

@import '/vendor/filament/filament/resources/css/theme.css';
 
@config 'tailwind.config.js';
 
.fi-main-ctn {
@apply bg-slate-100;
}
 
.fi-wi-stats-overview-stat {
@apply shadow-md;
}

Next, let's move the stats label and value to the right.

resources/css/filament/admin/theme.css:

@import '/vendor/filament/filament/resources/css/theme.css';
 
@config 'tailwind.config.js';
 
.fi-main-ctn {
@apply bg-slate-100;
}
 
.fi-wi-stats-overview-stat {
@apply shadow-md;
}
 
.fi-wi-stats-overview-stat div > div:nth-child(1) {
@apply justify-end;
}
 
.fi-wi-stats-overview-stat-label {
@apply text-base font-light capitalize;
}
 
.fi-wi-stats-overview-stat-value {
@apply flex justify-end tracking-tighter;
}


Styling Chart Widget

Styling a chart widget involves more than applying CSS styles. Filament uses the Chart.js library for showing charts, so some options are added to the chart itself.

First, let's use CSS to reverse the chart with the heading.

resources/css/filament/admin/theme.css:

@import '/vendor/filament/filament/resources/css/theme.css';
 
@config 'tailwind.config.js';
 
.fi-main-ctn {
@apply bg-slate-100;
}
 
.fi-wi-stats-overview-stat {
@apply shadow-md;
}
 
.fi-wi-stats-overview-stat div > div:nth-child(1) {
@apply justify-end;
}
 
.fi-wi-stats-overview-stat-label {
@apply text-base font-light capitalize;
}
 
.fi-wi-stats-overview-stat-value {
@apply flex justify-end tracking-tighter;
}
 
.fi-wi-chart {
@apply mt-4;
}
 
.fi-wi-chart > section {
@apply flex flex-col-reverse;
}

Next, let's add some background only to the chart and make it stand out from the widget itself.

resources/css/filament/admin/theme.css:

@import '/vendor/filament/filament/resources/css/theme.css';
 
@config 'tailwind.config.js';
 
.fi-main-ctn {
@apply bg-slate-100;
}
 
.fi-wi-stats-overview-stat {
@apply shadow-md;
}
 
.fi-wi-stats-overview-stat div > div:nth-child(1) {
@apply justify-end;
}
 
.fi-wi-stats-overview-stat-label {
@apply text-base font-light capitalize;
}
 
.fi-wi-stats-overview-stat-value {
@apply flex justify-end tracking-tighter;
}
 
.fi-wi-chart {
@apply mt-4;
}
 
.fi-wi-chart > section {
@apply flex flex-col-reverse;
}
 
.fi-wi-chart:has(.fi-section-content) .fi-color-custom {
@apply rounded-xl bg-gradient-to-b from-green-500 to-green-600 p-6 -mt-12;
}

But now, the text is difficult to read. This is where the options for the chart itself should be set. Let's set the text color to white.

app/Filament/Widgets/CustomersChart.php:

use Filament\Support\RawJs;
 
class CustomersChart extends ChartWidget
{
// ...
 
protected function getOptions(): array | RawJs | null
{
return [
'scales' => [
'x' => [
'ticks' => [
'color' => 'white',
],
],
'y' => [
'ticks' => [
'color' => 'white',
],
],
],
];
}
}

app/Filament/Widgets/OrdersChart.php:

use Filament\Support\RawJs;
 
class OrdersChart extends ChartWidget
{
// ...
 
protected function getOptions(): array | RawJs | null
{
return [
'scales' => [
'x' => [
'ticks' => [
'color' => 'white',
],
],
'y' => [
'ticks' => [
'color' => 'white',
],
],
],
];
}
}

That's better. What if we removed the legend? We know what those values are in the chart.

app/Filament/Widgets/CustomersChart.php:

use Filament\Support\RawJs;
 
class CustomersChart extends ChartWidget
{
// ...
 
protected function getOptions(): array | RawJs | null
{
return [
'plugins' => [
'legend' => false,
],
'scales' => [
'x' => [
'ticks' => [
'color' => 'white',
],
],
'y' => [
'ticks' => [
'color' => 'white',
],
],
],
];
}
}

app/Filament/Widgets/OrdersChart.php:

use Filament\Support\RawJs;
 
class OrdersChart extends ChartWidget
{
// ...
 
protected function getOptions(): array | RawJs | null
{
return [
'plugins' => [
'legend' => false,
],
'scales' => [
'x' => [
'ticks' => [
'color' => 'white',
],
],
'y' => [
'ticks' => [
'color' => 'white',
],
],
],
];
}
}

It looks much cleaner, in my opinion. Let's make one final customization: remove the fill and change the chart line color to white.

app/Filament/Widgets/CustomersChart.php:

class CustomersChart extends ChartWidget
{
// ...
 
protected function getData(): array
{
return [
'datasets' => [
[
'label' => 'Customers',
'data' => [4344, 5676, 6798, 7890, 8987, 9388, 10343, 10524, 13664, 14345, 15753, 17332],
'fill' => 'start',
'fill' => 'false',
'borderColor' => 'white',
],
],
'labels' => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
];
}
 
// ...
}

app/Filament/Widgets/OrdersChart.php:

class OrdersChart extends ChartWidget
{
// ...
 
protected function getData(): array
{
return [
'datasets' => [
[
'label' => 'Orders',
'data' => [2433, 3454, 4566, 3300, 5545, 5765, 6787, 8767, 7565, 8576, 9686, 8996],
'fill' => 'start',
'fill' => 'false',
'borderColor' => 'white',
],
],
'labels' => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
];
}
 
// ...
}


As you can see, changing styles is easy. The main requirement is to know CSS.