Filament 커스텀 테마: Vite, Tailwind, 그리고 사라진 CSS

TL;DR

  • ->colors()만으로는 폰트, 간격, 컴포넌트 스타일 커스텀 불가능. 결국 테마 만들어야 함
  • php artisan make:filament-theme 치면 끝… 이 아님. viteTheme() 등록과 vite.config.js 수정 두 가지 빠뜨리면 CSS가 증발함
  • Tailwind CSS 4.0부터 tailwind.config.js 없어짐. CSS 안에서 @theme, @source, @custom-variant로 전부 처리
  • PostCSS 플러그인도 바뀜. tailwindcss가 아니라 @tailwindcss/postcss를 써야 함
  • CSS가 안 나오면 99% 확률로 위 중 하나 빠뜨린 거임

왜 커스텀 테마가 필요한가

Panel Provider에서 ->colors()로 primary 색상 바꾸는 건 쉬움.

use Filament\Support\Colors\Color;

->colors([
    'primary' => Color::Amber,
])

여기까지는 평화로움. 근데 이런 요구사항이 들어오는 순간 끝남:

  • "사이드바 폰트 좀 바꿔주세요"
  • "버튼 border-radius를 전부 직각으로"
  • "다크 모드에서 배경색이 너무 칙칙해요"
  • "우리 브랜드 컬러가 Filament 프리셋에 없는데요"

->colors()는 Filament이 미리 정의해둔 color slot에 값을 끼워넣는 것뿐임. Tailwind 유틸리티 클래스를 직접 쓰거나, Filament 컴포넌트의 기본 스타일을 오버라이드하려면 커스텀 테마가 필요함.

그리고 이 커스텀 테마라는 게, 만드는 건 명령어 한 줄인데 작동시키는 데 2시간 삽질하게 됨.


make:filament-theme — 시작은 창대하나

php artisan make:filament-theme

실행하면 resources/css/filament/admin/theme.css 파일이 생김. 그리고 터미널에 친절하게 두 가지를 하라고 알려줌.

근데 아무도 그 메시지를 안 읽음.

나도 안 읽었음.

필수 설정 1: Panel Provider에 viteTheme 등록

// app/Providers/Filament/AdminPanelProvider.php

use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        ->default()
        ->id('admin')
        ->viteTheme('resources/css/filament/admin/theme.css')
        // ... 나머지 설정
    ;
}

이거 안 하면 Filament이 커스텀 CSS 존재 자체를 모름. 당연히 아무것도 안 바뀜. 에러도 안 남. 그냥 조용히 무시당함.

필수 설정 2: vite.config.js에 input 추가

// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: [
                'resources/css/app.css',
                'resources/js/app.js',
                'resources/css/filament/admin/theme.css', // ← 이거
            ],
            refresh: true,
        }),
    ],
});

이것도 안 하면 Vite가 테마 CSS를 빌드 대상으로 인식 못함. npm run build 해도 manifest에 안 들어감. 프로덕션에서 404 뜸.

두 가지 다 해야 함. 하나만 하면 안 됨. 둘 다 안 하면 당연히 안 됨.

터미널 출력에 다 써있었는데 Y 연타하느라 못 봤음. 고전적 삽질 패턴임.


Tailwind CSS 4.0: config 파일이 사라졌다

Filament v3 최신 버전은 Tailwind CSS 4.0을 사용함. 여기서 큰 변화가 있음.

전에는 이랬음 (Tailwind 3.x)

프로젝트/
├── tailwind.config.js     ← 여기서 색상, content 경로 설정
├── postcss.config.js      ← tailwindcss 플러그인 등록
└── resources/css/
    └── theme.css          ← @tailwind base; @tailwind components; ...

지금은 이러함 (Tailwind 4.0)

프로젝트/
├── postcss.config.js      ← @tailwindcss/postcss 플러그인 등록
└── resources/css/
    └── theme.css          ← 여기서 전부 다 함

tailwind.config.js가 없어짐. 설정이 CSS 안으로 들어감. "CSS-first configuration"이라고 부름.

theme.css가 하는 일

@import '/vendor/filament/filament/resources/css/theme.css';

@source '../../../../vendor/filament/**/*.blade.php';
@source '../../../../app/Filament/**/*.php';
@source '../../../../resources/views/filament/**/*.blade.php';

@custom-variant dark (&:is(.dark *));

@theme {
    --color-primary-50: oklch(0.98 0.02 85);
    --color-primary-500: oklch(0.65 0.16 85);
    --color-primary-950: oklch(0.18 0.06 85);
}
지시어 역할 빠뜨리면
@import Filament 기본 테마 CSS 가져옴 기본 스타일 전부 날아감
@source Tailwind가 클래스를 스캔할 파일 경로 프로덕션 빌드에서 클래스 purge됨
@custom-variant dark Filament의 다크 모드 선택자 정의 다크 모드 스타일 전멸
@theme CSS 변수(색상, 폰트 등) 정의 커스텀 디자인 토큰 미적용

Vite + PostCSS 셋업

postcss.config.js

export default {
    plugins: {
        '@tailwindcss/postcss': {},
    },
};

주의: 옛날 방식인 tailwindcss: {}가 아님. Tailwind 4.0에서는 @tailwindcss/postcss라는 별도 패키지를 씀.

npm install -D @tailwindcss/postcss tailwindcss@latest

옛날 블로그 보고 postcsstailwindcss 플러그인 등록하면 안 됨. 빌드는 되는데 CSS가 텅 빈 파일로 나옴. 에러 없이. 조용히.


CSS 사라지는 디버깅 모음집

2시간 삽질의 기록을 공유함. 누군가의 2시간을 아껴주길 바람.

1. npm run dev 안 돌렸음

Filament 테마는 Vite로 빌드됨. php artisan serve만 띄워놓고 왜 안 되지 하고 있었음. 별도 터미널에서 npm run dev 돌려야 함.

증상: 커스텀 CSS가 전혀 적용 안 됨. 근데 Filament 기본 스타일은 나옴.

2. @source 누락 — 프로덕션 purge 지옥

개발 중엔 잘 되는데 npm run build 후 배포하면 스타일이 날아감. Tailwind 4.0은 @source에 명시된 파일에서만 사용된 클래스를 감지함.

증상: 개발 환경에서는 완벽한데 프로덕션에서 레이아웃이 깨짐.

3. dark mode @custom-variant 빠뜨림

@custom-variant dark (&:is(.dark *));

이 한 줄이 없으면 다크 모드 전환해도 밝은 테마 색상이 그대로 남음.

4. @import 순서 — cascade 폭탄

@import를 먼저 하고 커스텀 @theme을 뒤에 둬야 내 값이 적용됨. CSS cascade는 뒤에 오는 게 이김.


실전 테마 예제: 한빛공방 브랜드 컬러

브랜드 컬러:

  • Warm Ochre (#C4882F) — 주 색상
  • Deep Walnut (#5C4033) — 보조 색상
  • Cream Ivory (#FFF8E7) — 배경

Color::hex()로 shade 자동 생성

->colors([
    'primary' => Color::hex('#C4882F'),
    'gray' => Color::hex('#5C4033'),
])

Color::hex()는 입력한 hex 값 기준으로 50~950까지의 shade를 자동 생성해줌.

사이드바 배경이나 그라데이션은 테마 CSS에서:

@theme {
    --color-gray-50: #FFF8E7;
    --font-sans: 'Pretendard', sans-serif;
}

.fi-sidebar {
    background: linear-gradient(180deg, #FFF8E7 0%, #F5E6C8 100%);
}

.dark .fi-sidebar {
    background: linear-gradient(180deg, #2C1810 0%, #1A0F09 100%);
}

CSS 넣는 위치 판단 기준

변경하고 싶은 것 위치
primary, danger 등 색상 변경 Panel Provider ->colors()
색상의 특정 shade만 미세 조정 theme.css @theme
폰트 변경 theme.css @theme
컴포넌트 스타일 오버라이드 theme.css (일반 CSS)
레이아웃 구조 변경 Blade 뷰 퍼블리시

판단 기준: 값만 바꾸면 ->colors() 또는 @theme, 선택자 필요하면 theme.css에 CSS, HTML 구조 바꿔야 하면 Blade 퍼블리시.


체크리스트

테마 적용 후 아무것도 안 바뀌면 이 순서대로:

  1. make:filament-theme 실행했는가
  2. Panel Provider에 ->viteTheme() 등록했는가
  3. vite.config.js에 theme.css 경로 추가했는가
  4. postcss.config.js@tailwindcss/postcss 등록했는가
  5. @import가 최상단인가
  6. @source 경로 정확한가
  7. @custom-variant dark 선언했는가
  8. npm run dev 돌리고 있는가

8개 중 하나라도 빠지면 CSS가 사라짐. 에러 없이. 이게 이 주제의 본질임.


FAQ

Q: npm run devnpm run build 차이?

dev는 실시간 감시, build는 프로덕션 최적화 빌드. dev에서 잘 되던 게 build에서 깨지는 경우가 있으니 (주로 @source 누락) 배포 전에 반드시 build로 확인.

Q: 여러 패널에 각각 다른 테마 적용 가능?

됨. php artisan make:filament-theme app으로 패널별 테마 생성 후 각각 ->viteTheme()vite.config.js에 등록.


이전: Panel Provider 해부

다음: 내비게이션 & 멀티패널

이 글은 Building with Filament 시리즈의 네 번째 글입니다.