Skip to content
푸땡로그
Go back

Shadcn Lint: AI가 Tailwind 디자인 시스템을 임의로 바꾸지 못하게 하는 방법

AI 코딩 에이전트는 화면을 빠르게 만들지만, 기존 컴포넌트의 여백·색상·모서리 규칙을 무시한 유틸리티 클래스를 추가하기 쉽습니다. Shadcn Lint ↗는 이 문제를 Tailwind 디자인 시스템의 린트 규칙으로 바꾸고, 위반한 에이전트에게 프로젝트에서 써야 할 대안을 알려줍니다.

이 글은 제공된 영상 Shadcn Lint 써서 AI로 디자인 박살내지 않기 ↗와 공식 저장소를 바탕으로, React·Tailwind 프로젝트에서 시작할 수 있는 최소 설정과 규칙을 설명합니다.

기준: 2026.10.06 · @shadcn/lint 공식 저장소를 확인했습니다.


AI가 만든 UI는 왜 디자인 시스템에서 벗어날까

에이전트는 요구한 화면을 만들기 위해 p-4, bg-pink-500, rounded-[13px] 같은 클래스를 바로 추가할 수 있습니다. 페이지 하나만 보면 동작하지만, Button이나 Card가 이미 책임지는 크기·색상·형태를 호출하는 쪽에서 다시 정하면 컴포넌트 API가 흐려집니다.

TypeScript로 style prop을 좁힐 수도 있습니다. 그러나 타입 오류는 보통 padding을 쓸 수 없다는 사실만 알려 줍니다. Shadcn Lint는 왜 금지됐는지와 함께 size variant, 부모의 gap, 테마 토큰처럼 다음 선택지를 오류 메시지에 담을 수 있습니다.


Shadcn Lint가 검사하는 것

Shadcn Lint는 Tailwind v4 프로젝트용 agent-first linter입니다. shadcn/ui를 쓰지 않아도 React·Vue·Svelte와 ESLint 또는 Oxlint에서 사용할 수 있습니다. 컴포넌트와 테마를 다시 작성하지 않고 프로젝트별 계약(contract)을 설정하는 방식입니다.

공식 저장소는 다음 규칙을 제공합니다.

영상에서 제시하는 문제도 여기에 있습니다. AI에게 디자인을 맞춰 달라고만 요청하면 규칙을 기억에 의존하게 됩니다. 검사 가능한 계약을 두면 에이전트의 구현 뒤에 같은 기준을 다시 적용할 수 있습니다.


React와 ESLint에서 최소 설정하기

Node.js 20.19 이상, ESLint 9.30 이상이 필요합니다. 기존 ESLint 설정이 있다면 parser 설정은 유지하고 플러그인과 규칙만 추가합니다.

먼저 개발 의존성으로 설치합니다.

npm install -D @shadcn/lint eslint @typescript-eslint/parser

다음은 공식 문서를 바탕으로 구성한 최소 eslint.config.mjs 예제입니다.

import { plugin as shadcn } from "@shadcn/lint";
import tsParser from "@typescript-eslint/parser";
import { defineConfig } from "eslint/config";

export default defineConfig([
  {
    files: ["**/*.{js,jsx,ts,tsx}"],
    languageOptions: {
      parser: tsParser,
      parserOptions: { ecmaFeatures: { jsx: true } },
    },
    plugins: { shadcn },
    rules: {
      "shadcn/no-arbitrary-values": "error",
    },
  },
]);

설정 뒤에는 프로젝트의 lint 명령으로 검사합니다.

npx eslint .

이 명령은 공식 문서 기준 예시입니다. 기존 저장소에 ESLint 구성이 있다면 새 파일로 덮어쓰지 말고 현재 설정에 병합합니다.


Button이 책임지는 스타일을 계약으로 만들기

처음에는 규칙 하나만 켜기보다, 컴포넌트마다 호출부가 바꿀 수 있는 범위를 정하는 편이 좋습니다. 예를 들어 Button은 페이지 배치를 위한 margin과 full width만 허용하고 padding·높이·모서리는 Button 구현이 관리하게 할 수 있습니다.

"shadcn/no-restyle": ["error", {
  allow: ["layout"],
  contracts: [
    {
      pattern: "^Button$",
      allow: ["w-full", "mt-*", "mb-*"],
    },
  ],
}],

이 계약 아래에서 size=“lg”와 className=“mt-4 md:w-full”은 허용할 수 있습니다. 반면 className=“p-4 hover:rounded-full”은 Button이 맡아야 할 여백과 형태를 호출부에서 바꾸므로 오류가 됩니다.

오류가 났을 때 에이전트가 할 일을 알 수 있어야 합니다. message에 size prop을 사용한다는 팀 규칙을 넣고, variant·테마 파일 위치를 안내하면 린트 결과가 수정 지시가 됩니다.


도입 순서: 금지보다 합의부터

기존 프로젝트에 바로 모든 규칙을 error로 두면 이미 쌓인 예외가 한꺼번에 드러납니다. 다음 순서로 범위를 좁힙니다.

  1. 디자인 시스템이 관리하는 컴포넌트와 호출부가 조절할 속성을 정합니다.
  2. no-arbitrary-values 또는 no-raw-colors 하나를 먼저 켜서 토큰 밖 값이 쓰이는 위치를 확인합니다.
  3. Button, Card처럼 재사용이 잦은 컴포넌트에 no-restyle 계약을 추가합니다.
  4. 오류 메시지에 실제 variant와 테마 토큰을 넣습니다.
  5. 에이전트의 작업 지침에 lint 실행과 오류 수정 단계를 넣습니다.

컴포넌트를 고정해 버리는 것이 목적은 아닙니다. 화면마다 필요한 배치와 콘텐츠 변화는 허용하되, 컴포넌트가 책임지는 색상·간격·형태가 여러 화면에서 제각각 되지 않게 하는 것이 목적입니다.


언제 쓰면 좋은가

Tailwind와 재사용 컴포넌트가 있고, AI 에이전트가 UI 파일을 자주 바꾸는 팀에 잘 맞습니다. 같은 컴포넌트를 여러 제품에서 쓰되 프로젝트마다 허용 범위가 다르다면 설정을 공유하거나 확장할 수도 있습니다.

반대로 디자인 토큰과 컴포넌트 책임이 아직 정리되지 않았다면, 린터가 먼저 답을 만들 수는 없습니다. Button의 크기·색상·variant가 무엇인지 합의한 뒤 그 합의를 계약으로 옮겨야 합니다. CSS 전체를 검사하려면 별도의 CSS 린터도 함께 고려합니다. 공식 문서에 따르면 Vue와 Svelte의 style 블록은 이 도구의 검사 대상이 아닙니다.


기록해 둘 내용

Shadcn Lint의 차이는 디자인 위반을 찾는 데서 끝나지 않는다는 점입니다. 프로젝트의 컴포넌트·variant·테마를 바탕으로 수정 방향을 제공해, AI 에이전트가 다음 반복에서 같은 기준을 적용하게 합니다.

처음에는 한두 컴포넌트와 한 개 규칙으로 시작해 오류 메시지가 팀의 실제 선택지를 가리키는지 확인합니다. 그 다음에 규칙 범위를 넓히면 디자인 시스템을 코드 리뷰의 기억에만 맡기지 않을 수 있습니다.


참고 자료


Share this post on:

Previous Post
OpenAI DevDay 2026: GPT-6.1 Sol·Dots·Pro 500, 개발자는 무엇을 선택할까
Next Post
Claude Code의 다음 메시지 제안: 학습 데이터 논쟁과 사용 기준