-
Notifications
You must be signed in to change notification settings - Fork 264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Content] Add diogogpinto-filament-themes-full-guide.md content and respective art #587
base: main
Are you sure you want to change the base?
Changes from all commits
cd73873
af8f36d
b2c271d
6b5a38e
72f2c3d
261df8e
96cd409
2270af5
ff71373
836f4a0
5a52631
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,331 @@ | ||
--- | ||
title: "Filament Custom Themes - The Full Guide" | ||
slug: diogogpinto-filament-themes-full-guide | ||
author_slug: diogogpinto | ||
publish_date: 2024-10-29 | ||
categories: [panel-builder] | ||
type_slug: article | ||
--- | ||
|
||
Welcome to this "full guide" on how to create a custom theme in Filament v3. | ||
|
||
Are you looking to elevate your Filament v3 Panels with a unique appearance? This in-depth guide will take you beyond the basics covered in the official documentation. | ||
|
||
## Resources | ||
|
||
I would recommend checking the following resources if you haven't already. | ||
|
||
- [Filament Official Documentation](https://filamentphp.com/docs/) | ||
- [Filament Official Documentation on Themes](https://filamentphp.com/docs/3.x/panels/themes#creating-a-custom-theme) | ||
- [Filament Official Documentation on Style Customization](https://filamentphp.com/docs/3.x/support/style-customization) | ||
- [Tailwind Official Documentation](https://tailwindcss.com/docs/installation) | ||
|
||
## Before You Start | ||
|
||
I am assuming you already have a Filament Panel setup. If you don't have one, please set up a panel using the [official documentation guide](https://filamentphp.com/docs/3.x/panels/getting-started). | ||
|
||
## Creating a theme | ||
|
||
In this example, we will be creating a custom theme for Filament's default panel, the `admin` panel. | ||
|
||
> [!note] | ||
> The same steps apply for any other panel you may have in your Filament project | ||
|
||
### Creating the theme using the terminal | ||
|
||
In your project's root directory, run: | ||
|
||
```bash | ||
php artisan make:filament-theme | ||
``` | ||
|
||
It will scan your app for all the panels you have installed and let you select which panel this theme applies to. Select the panel you wish to customize. In this particular case, we will select the panel `admin`. | ||
|
||
![Create Theme Terminal Command](/images/content/articles/diogogpinto-filament-themes-full-guide/create-theme.webp) | ||
|
||
After you've selected the panel, the terminal will give you all further instructions, but we'll go by each one step by step. | ||
|
||
![After Creating the Theme](/images/content/articles/diogogpinto-filament-themes-full-guide/after-create-theme.webp) | ||
|
||
#### Editing vite.config.js | ||
|
||
Go to the `vite.config.js` file in your Laravel project's root directory and set the input array like below: | ||
|
||
```javascript | ||
import { defineConfig } from 'vite' | ||
import laravel, { refreshPaths } from 'laravel-vite-plugin' | ||
|
||
export default defineConfig({ | ||
plugins: [ | ||
laravel.default({ | ||
input: [ | ||
'resources/css/app.css', | ||
'resources/js/app.js', | ||
// Add the following line of code | ||
'resources/css/filament/admin/theme.css' // [tl! add] | ||
], | ||
refresh: [ | ||
...refreshPaths, | ||
'app/Filament/**', | ||
'app/Forms/Components/**', | ||
'app/Livewire/**', | ||
'app/Infolists/Components/**', | ||
'app/Providers/Filament/**', | ||
'app/Tables/Columns/**', | ||
], | ||
}), | ||
], | ||
}) | ||
``` | ||
|
||
See how we've added `resources/css/filament/admin/theme.css` to that array? This will tell vite where our custom theme is located when running the build process. | ||
|
||
>[!note] | ||
> If you have other themes for other panels, you can add them in the same array. This vite config file can contain as many themes for as many panels as you like! | ||
|
||
#### Registering the viteTheme() on our panel | ||
|
||
Now we shall edit the `AdminPanelProvider.php` file and add the viteTheme method to our `$panel`, like the example below: | ||
|
||
```php | ||
return $panel | ||
->id('admin') | ||
->viteTheme('resources/css/filament/admin/theme.css') // [tl! add] | ||
``` | ||
|
||
Our panel now knows we are using a custom theme and where in the filesystem to find it. | ||
|
||
#### Running the build process | ||
|
||
![Build Process](/images/content/articles/diogogpinto-filament-themes-full-guide/npm-run-build.webp) | ||
|
||
At last, we shall run the build process with the terminal in our Laravel project's root directory: | ||
|
||
```bash | ||
npm run build | ||
``` | ||
|
||
### Registering vendor files from Filament Plugins | ||
|
||
Sometimes, when installing plugins like [Auth UI Enhancer](https://www.github.com/diogogpinto/filament-auth-ui-enhancer) or [Filament Curator](https://github.com/awcodes/filament-curator), for example, the docs may say something to the effect of: | ||
|
||
> 1. Add the plugin's views to your tailwind.config.js file. | ||
> ```javascript | ||
> content: [ | ||
> './vendor/diogogpinto/filament-auth-ui-enhancer/resources/**/*.blade.php', | ||
> ] | ||
> ``` | ||
|
||
#### What does this mean? | ||
|
||
We need to make sure that, when we start the build process, `vite` will check the files in the paths specified in our `content` array, instructing `vite` to collect all CSS classes in the plugin views. It will then compile all used CSS classes into the one single CSS file for your Filament panel. | ||
|
||
So in our case, when installing the `Auth UI Enhancer` and `Curator` plugins in our panel, we will go to `resources/css/filament/admin/tailwind.config.js` and edit it like the code below: | ||
|
||
```js | ||
import preset from '../../../../vendor/filament/filament/tailwind.config.preset' | ||
|
||
export default { | ||
presets: [preset], | ||
content: [ | ||
'./app/Filament/Clusters/Products/**/*.php', | ||
'./resources/views/filament/clusters/products/**/*.blade.php', | ||
'./vendor/filament/**/*.blade.php', | ||
'./vendor/diogogpinto/filament-auth-ui-enhancer/resources/**/*.blade.php', // [tl! add] | ||
'./vendor/awcodes/filament-curator/resources/**/*.blade.php', // [tl! add] | ||
], | ||
} | ||
``` | ||
|
||
Additionally, in the case of the `Curator` plugin, the author requires you to import some CSS files in your `theme.css`. This can be done, by editing the file `resources/css/filament/admin/theme.css` and making it look like the snippet below: | ||
|
||
```css | ||
@import '/vendor/filament/filament/resources/css/theme.css'; | ||
@import '/node_modules/cropperjs/dist/cropper.css'; // [tl! add] | ||
@import '/vendor/awcodes/filament-curator/resources/css/plugin.css'; // [tl! add] | ||
|
||
@config 'tailwind.config.js'; | ||
``` | ||
|
||
This last step imports all custom classes needed by the plugin to render correctly. It imports the classes, puts them into our panel's unique CSS file, and minimizes the CSS for greater performance. | ||
|
||
#### Running the build process | ||
|
||
When installing plugins and editing any theme related files, always remember to run `npm run build` when you're finished to compile all the assets. | ||
|
||
## Customizing the theme | ||
|
||
Both Laravel and Filament (being Laravel based), offer multiple solutions to the same problem. Because of that, we will look at two ways of building your own Filament look and feel: the recommended way and the not-so-recommended way. | ||
|
||
### Before starting the customization process | ||
|
||
While you develop your theme, you should run `npm run dev` in the root of your project. This process watches for changes in the files registered in the `vite.config.js` (and `tailwind.config.js`, by extension) and automatically renders any changes on file save. | ||
|
||
> [!note] | ||
> You still need to run `npm run build` when you're finished customizing your theme | ||
|
||
### The recommended way to customize your theme | ||
|
||
Every component in the Panel Builder package, including the layout, forms, infolists and tables, are wrapped in custom classes to make it possible to customize the panel's look and feel. Let's look at the following example: | ||
|
||
![Breadcrumb Example](/images/content/articles/diogogpinto-filament-themes-full-guide/breadcrumb-example.webp) | ||
|
||
Looking at the breadcrumb component with Chrome's built-in Developer Tools > Inspect Element, you can see that the `<nav>` tag contains the following classes: | ||
|
||
```html | ||
<nav class="fi-breadcrumbs mb-2 hidden sm:block"> | ||
``` | ||
|
||
The `.fi-breadcrumbs` class allows us to further optimize the breadcrumbs' look and feel. By default, the class has no CSS properties defined–it only exists for us to apply custom styles. | ||
|
||
#### Customizing the CSS | ||
|
||
Using the above example of `.fi-breadcrumbs`, we now apply custom CSS classes in our `theme.css` file to change the styling of the breadcrumbs. You can either use Tailwind utility classes or vanilla CSS. Let's say you want to override the default margin `mb-2`. Either option in the below CSS will yield the exact same results: | ||
|
||
```css | ||
.fi-breadcrumbs { | ||
@apply mb-4; | ||
} | ||
|
||
.fi-breadcrumbs { | ||
margin-bottom: 1rem; | ||
} | ||
``` | ||
|
||
As the `.fi-breadcrumbs` class is inserted before the default Tailwind utility classes, applying custom CSS will always override the default style. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above comment, but I believe the order in which a class string is laid out has no bearing on specificity or the cascade, so having multiple classes of the same specificity may lead to unreliable outputs based on where the Tailwind classes are defined in relation to one another. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup, totally depends on specificity. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm probably missing something, given that both TW classes and custom classes created with @apply are technically single class selectors, shouldn’t they all have equal specificity? I clearly made a mistake in the text, as it isn't order of declaration that matters, but the build process that builds custom classes after the utility classes. Hope to get some clarity, thank you in advance! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @zepfietje hey Zep, sorry for pinging you on this, but just so I can ship the changes, in the text I'm considering saying something like:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think this makes sense? |
||
|
||
#### Diving deeper | ||
|
||
If we dive deeper into the breadcrumbs, we will find all the following classes, in this hierarchy: | ||
|
||
``` | ||
- .fi-breadcrumbs | ||
-- .fi-breadcrumbs-list | ||
--- .fi-breadcrumbs-item | ||
---- .fi-breadcrumbs-item-separator | ||
---- .fi-breadcrumbs-item-label | ||
``` | ||
|
||
Let's say we want to really change the breadcrumbs appearance. We can style each of this classes. Check the following example: | ||
|
||
```css | ||
.fi-breadcrumbs-list { | ||
@apply gap-x-0; | ||
} | ||
|
||
.fi-breadcrumbs-item { | ||
@apply gap-x-0; | ||
} | ||
|
||
.fi-breadcrumbs-item-label { | ||
@apply font-thin dark:text-primary-500 text-primary-500; | ||
} | ||
|
||
span.fi-breadcrumbs-item-label { | ||
@apply border-b-2 border-b-primary-500 font-semibold -mb-[2px]; | ||
} | ||
Comment on lines
+220
to
+226
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is confusing as to why you have the same class twice, with one being more specific due to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alexandersix I believe in this case breadcrumbs active item is wrapped in a Maybe something like the following would be better? .fi-breadcrumbs-list > li:last-child .fi-breadcrumbs-item-label Will have to try it out. |
||
|
||
.fi-breadcrumbs-item-separator { | ||
@apply fill-primary-500 h-4; | ||
} | ||
``` | ||
|
||
![Breadcrumbs Final Example](/images/content/articles/diogogpinto-filament-themes-full-guide/breadcrumbs-final.webp) | ||
|
||
There are many classes within each Filament component. You can go through each one and apply your custom CSS to create a unique design for your Panel. | ||
|
||
> [!TIP] | ||
> There's a useful Filament Plugin ([Theme Inspector](https://filamentphp.com/plugins/codewithdennis-theme-inspector)) that lets you inspect all the classes in your panel in your dev environment. You can even copy to clipboard! It really smoothes out the theme development process. | ||
|
||
### Going beyond CSS | ||
|
||
Sometimes there are some things your theme requires that go beyond CSS. You may want to add a custom Livewire component, Blade View, or JS script. All of this is possible, but as these modifications are outside the scope of this guide, I would advise you to check the following resources: | ||
|
||
- [Render Hooks on the Official Docs](https://filamentphp.com/docs/3.x/support/render-hooks) - Render custom views almost anywhere in your panels | ||
- [Registering Assets](https://filamentphp.com/docs/3.x/support/assets#registering-javascript-files) - Register custom CSS/JS in your Filament panels | ||
|
||
### The non-recommended way to customize your theme | ||
|
||
Another way of doing things, is publishing all the views of the Filament panels package. Why isn't this recommended? The docs say exactly why: | ||
|
||
> You may be tempted to publish the internal Blade views to your application so that you can customize them. We don't recommend this, as it will introduce breaking changes into your application in future updates. Please use the CSS hook classes wherever possible. | ||
> If you do decide to publish the Blade views, please lock all Filament packages to a specific version in your composer.json file, and then update Filament manually by bumping this number, testing your entire application after each update. This will help you identify breaking changes safely. | ||
|
||
> [!warning] | ||
> This is for demonstration purposes only, you really shouldn't do this as it can break your panels in future releases/updates. If you need to do this, only publish the necessary files and lock filament to your project's current version | ||
|
||
So, if you were to do this, you could run the following command in your terminal: | ||
|
||
```bash | ||
php artisan vendor:publish --tag=filament-panels-views | ||
``` | ||
|
||
Now, you will find a bunch of files inside your `resources/views/vendor/filament-panels` folder. These are the original view files you can (but shouldn't) customize. | ||
|
||
![Vendor Files](/images/content/articles/diogogpinto-filament-themes-full-guide/vendor-publish.webp) | ||
|
||
Navigate to your themes `tailwind.config.js` and add the filament-panels folder to the content array, so vite can process these file changes. If you're following along, your file should look like this: | ||
|
||
```js | ||
import preset from '../../../../vendor/filament/filament/tailwind.config.preset' | ||
|
||
export default { | ||
presets: [preset], | ||
content: [ | ||
'./app/Filament/Clusters/Products/**/*.php', | ||
'./resources/views/filament/clusters/products/**/*.blade.php', | ||
'./vendor/filament/**/*.blade.php', | ||
'./vendor/diogogpinto/filament-auth-ui-enhancer/resources/**/*.blade.php', | ||
'./vendor/awcodes/filament-curator/resources/**/*.blade.php', | ||
'./resources/views/filament-panels/**/*.blade.php', // [tl! add] | ||
], | ||
} | ||
``` | ||
|
||
#### Example - make the topbar backdrop blur | ||
|
||
If you're editing the blade files directly, to blur the background of a topbar, you should open the following file: | ||
|
||
``` | ||
./resources/views/vendor/filament-panels/components/topbar/index.php | ||
``` | ||
|
||
Now we can edit the `<nav>` tag, and make it look like the following: | ||
|
||
```html | ||
<nav | ||
class="flex h-16 items-center gap-x-4 bg-white bg-opacity-50 backdrop-blur-lg px-4 shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:bg-opacity-50 dark:ring-white/10 md:px-6 lg:px-8" | ||
> | ||
``` | ||
|
||
To make it look consistent in the sidebar, we should also open the following file: | ||
|
||
``` | ||
./resources/views/vendor/filament-panels/components/sidebar/index.php | ||
``` | ||
|
||
And change the `<header>` tag to make it look like: | ||
|
||
```html | ||
<header | ||
class="fi-sidebar-header flex h-16 items-center bg-white bg-opacity-50 backdrop-blur-lg px-6 ring-1 ring-gray-950/5 dark:bg-gray-900 dark:bg-opacity-50 dark:ring-white/10 lg:shadow-sm" | ||
> | ||
``` | ||
|
||
And there it is. We were able to customize the theme file in the unrecommended way. We shouldn't really do this, unless we want to add complex logic to our code and take on the burden of updating these files every single time Filament updates. If this is the case, you can delete all the files except the ones you are directly going to modify. | ||
|
||
![Blade editing adding backdrop](/images/content/articles/diogogpinto-filament-themes-full-guide/blade-backdrop-blur.webp) | ||
|
||
> [!note] | ||
> All the changes you make to these files will render on ALL of your Filament panels in the project, unless you use some kind of conditional statements in your blade files. | ||
|
||
Remember to do the things the right way whenever possible. | ||
|
||
## Support | ||
|
||
If you want support on creating a theme, I would recommend the following channels: | ||
|
||
- [Filament Github Discussions](https://github.com/filamentphp/filament/discussions) | ||
- [Filament Official Discord](https://filamentphp.com/discord) | ||
|
||
You can also reach me on Discord or [Twitter](https://www.twitter.com/diogogpinto) if you have any questions regarding this particular guide and have any doubts regarding this process. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually think this isn't necessarily always going to work.
I believe that, specifically referencing the bottom margin, we won't reliably be able to override the CSS styling. This is because there is already a
mb-2
class in the class string, so when our styles get applied via.fi-breadcrumbs
,mb-2
and ourmb-4
will (theoretically) have the same specificity. If that is the case, whichever class is defined further down in the cascade with take precedence.I might be wrong here, but regardless it may be worth changing this example from an "overriding" example to an "adding" example. Something like adding a top padding, border, etc.
@zepfietje (or anyone from Core), let me know if I'm completely incorrect here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alexandersix just wondering, given that the custom classes are always defined after TW classes, wouldn't they always take precedence? Or is there a case where that may not be true?
I may be missing something