[Next.js] xlsx-js-style 사용해서 엑셀(Excel) 다운로드 기능 구현 및 스타일 적용

옹잉·2025년 6월 18일
1

⚒️ 설치

yarn add xlsx-js-style

스타일 없이 엑셀 다운로드만 하려고 하면 간단히 구현 가능하다
실제로 몇 분 안걸렸다!

그때는 스타일 줄 생각을 안하고 있어서 xlsx로 진행했는데 xlsx-js-style이 xlsx 포크해서 개발된거라 api가 거의 동일하다

만약 스타일 적용 안하고 간단하게만 사용할 예정이라면 xlsx 공식문서

npm i --save https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz

or

yarn add https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz

아래는 추출 할 데이터이다.

const header = [
  '배송지 구분 번호',
  '배송지명',
  '배송지 주소',
  '수령인',
  '택배사',
  '송장번호',
  '비고',
];

const body = [
  {
    deliveryTypeNumber: '1',
    deliveryName: '서울',
    deliveryAddress: '서울시 강남구',
    recipient: '홍길동',
    courierCompany: 'CJ대한통운',
    trackingNumber: '1234567890',
    notes: '특별 요청 없음',
  },
  {
    deliveryTypeNumber: '2',
    deliveryName: '부산',
    deliveryAddress: '부산시 해운대구',
    recipient: '김철수',
    courierCompany: '한진택배',
    trackingNumber: '0987654321',
    notes: '빠른 배송 요청',
  },
  {
    deliveryTypeNumber: '3',
    deliveryName: '대구',
    deliveryAddress: '대구시 수성구',
    recipient: '이영희',
    courierCompany: '롯데택배',
    trackingNumber: '1122334455',
    notes: '문 앞에 놓아주세요',
  },
];

💡 사용법

기본 엑셀 추출

import { utils, WorkBook, writeFileXLSX } from 'xlsx'; // xlsx-js-style 동일

const ExportExcel = () => {
  const handleExport = useCallback(() => {
    const wb:WorkBook  = utils.table_to_book([...header,...body]);
    writeFileXLSX(wb, '파일명.xlsx');
  }, []);

    return (
     <div className="w-120pxr">
       <Button onClick={handleExport}>Export</Button>
     </div>
  );
};

export default ExportExcel;

간단히는 이렇게 가능하다

시트명 커스텀 추출

만약 시트를 생성해서 시트명과 함께 파일로 추출하고 싶다면

import { utils, WorkBook, writeFileXLSX } from 'xlsx'; // xlsx-js-style 동일

const ExportExcel = () => {
  const handleExport = useCallback(() => {
    const ws = utils.aoa_to_sheet([...header,...body]);

    const wb: WorkBook = utils.book_new();
    utils.book_append_sheet(wb, ws, '원하는 시트명');
    writeFileXLSX(wb, '파일명.xlsx');
  }, []);

    return (
     <div className="w-120pxr">
       <Button onClick={handleExport}>Export</Button>
     </div>
  );
};

export default ExportExcel;

이렇게 시트 생성 후 파일 추출할 수도 있다.

스타일 적용

근데 스타일을 주려고 하니까 xlsx에서는 지원하지 않는게 많아서(아마 pro를 사용해야 하는 듯;)

xlsx-js-style라이브러리를 사용했다

설치방법은 최상단에 적어뒀으니까 생략하고

import { utils, WorkBook , writeFile } from 'xlsx-js-style';

const ExportExcel = () => {
  const handleExport = useCallback(() => {
    const ws = utils.aoa_to_sheet([...header,...body]);

    const borderStyle = {
      top: { style: 'thin', color: { rgb: '000000' } },
      bottom: { style: 'thin', color: { rgb: '000000' } },
      left: { style: 'thin', color: { rgb: '000000' } },
      right: { style: 'thin', color: { rgb: '000000' } },
    };

     // 헤더 스타일
       header.forEach((_, colIdx) => {
      const addr = utils.encode_cell({ r: 0, c: colIdx });
      if (ws[addr]) {
        ws[addr].s = {
          fill: { fgColor: { rgb: 'D9D9D9' } },
          font: { bold: true },
          border: borderStyle,
          alignment: { horizontal: 'center', vertical: 'center' },
        };
      }
    });

   // body 스타일
    for (let r = 1; r < wsData.length; r++) {
      for (let c = 0; c < header.length; c++) {
        const addr = utils.encode_cell({ r, c });
        if (ws[addr]) {
          ws[addr].s = {
            border: borderStyle,
            alignment: { vertical: 'center', horizontal: 'left' },
          };
        }
      }
    }

  // 열 너비
    const colWidths = [100, 80, 300, 80, 100, 80, 120, 150];
    ws['!cols'] = header.map((_, idx) => ({
      wpx: colWidths[idx] ?? 80,
    }));

    const wb: WorkBook = utils.book_new();
    utils.book_append_sheet(wb, ws, '원하는 시트명');
    writeFile(wb, '파일명.xlsx');
  }, []);

    return (
     <div className="w-120pxr">
       <Button onClick={handleExport}>Export</Button>
     </div>
  );
};

export default ExportExcel;

⚠️ 주의 사항

여기서 스타일 적용을 위해 가~~~장 중요한건
위의 xlsx 라이브러리 사용할때와 차이점이 있다.

그 전에는 스타일을 신경쓰지 않아서 공식문서(https://docs.sheetjs.com/docs/#export-an-html-table-to-excel-xlsx)에 나온대로 writeFileXLSX를 사용했다

그런데 xlsx-js-style를 사용해도 스타일이 적용 안되고, 간단한 예제를 적용해봐도 안돼서 엄청 삽질했다..

그러던중 공식문서(https://github.com/gitbrent/xlsx-js-style/?tab=readme-ov-file#cell-style-example) 예제를 따라하는데 writeFile 를 사용하는거였다..

이렇게 간단히 해결되는 문제였다니.. 문서를 좀 더 꼼꼼히 봐야할 필요가 있다..

profile
틀리더라도 🌸🌈🌷예쁘게 지적해주세요💕❣️

0개의 댓글