Below you can see a page of my bullet journal.

The layout is very efficient, but I have to draw the lines and fill in all calendar days by hand! Thus, for the next year, I would like to build a similar calendar with latex or another program.

The following features are important:

  • Days in columns (e.g. 30/9 Mo), one week, spanning half an A5 page. With vertical lines down.
  • Week number in the top right corner.
  • Few horizontal lines at the bottom. This is the habit tracker. About 3 lines are good.

Extra points:

  • The left side should be empty; however, a very decent grid helps to place notes.
  • Such a grid would also be helpful on the right side.
  • A tiny month calendar on the top left would be awesome!

Any idea on how to start?

Thanks, Robert

Example page of bullet journal

  • 3
    TikZ has all what you need, calendar functions, lines, tables. Have a look to the pgfmanual on CTAN. Sep 9, 2021 at 20:11

2 Answers 2


A good starting point for the calendar would be latex-yearly-planner repo on GitHub. It has a weekly view where there are three columns for days. As for the habit tracker, check the 100-Days-Challenge-Template repo on GitHub.

Those two repos should give you enough ideas and code on how to start. If you do continue with your project, please share an update as it looks very interesting.

  • geometry and class options for proper page setup
  • babel and translator for localized names
  • tikz for … TikZ
  • ext.calendar-plus for week numbers

Very first page is empty, then every even (left) page is just the grid and every odd (right) page is a calendar with very specialized nodes and hooks.

The grid is set to a 5mm while the day columns are 1cm wide. The height of these nodes need to be setup in relation to that so that grid inside the columns line up with the grid on the right side of the days as well as the opposite page.

You need to figure out the Monday of your first week yourself as well as the number of weeks. (Yes, we could calculate this but you only need to do that once a year for the next calendar so why bother?)


\documentclass[a5paper, twoside, ngerman]{article}
\usepackage{babel, translator}
\newcommand*\STARTDATE{2023-01-02}% ← Woohoo! Set first Monday of calendar here.
\setlength{\parindent}{0pt}% no \noindent
  every picture/.append style={
    trim left=+0pt, trim right=+\textwidth, baseline=+.3\baselineskip},
  every grid/.append style={
    line cap=round, dash pattern=on +0pt off +\pgfkeysvalueof{/tikz/grid size},
    xstep=+\pgfkeysvalueof{/tikz/grid size}, ystep=+0mm},
  every line/.append style={gray},
  every diag line/.style={gray, very thin, shorten >=+2mm, shorten <=+2mm},
  day width/.initial=1cm,
  grid size/.initial=5mm,
  execute at begin day scope={
    \tikzset{shift=(@.north east)}
    \draw[every line] (0,0) --++(down:\textheight);},
  execute after day scope={%
    \coordinate (@) at ([xshift=\pgfkeysvalueof{/tikz/day width}]@);
      \node[every week];
      \draw[every line] (@d.north east) --++(down:\textheight);
      \draw[every grid] (@d.north east) grid (O-|@w);           }{}},
  every day/.style={
    outer sep=+0pt, minimum height=+6mm, % hard-coded
    text width=
      \pgfkeysvalueof{/tikz/day width}-2*(\pgfkeysvalueof{/pgf/inner xsep}},
  every day (day)/.style={
    every day, align=left,
    at=(@), anchor=north west,
    name=@d, node contents={\%d=}},
  every day (month)/.style={
    every day, align=right,
    at=(@d.south west), anchor=north west, yshift=+2mm, % hard-coded
    name=@m, node contents={\%m=}},
  every weekday/.style={
    at=(@m.south west), anchor=north west,
    minimum width=\pgfkeysvalueof{/tikz/day width},
    minimum height=\pgfkeysvalueof{/tikz/grid size},
    text depth=+0pt, name=@wd, node contents={\%w.}},
  every week/.style={
    at={(\textwidth,\textheight)}, anchor=north east,
    name=@w, node contents={\%n=}},
  day code={
    \node[every day (day)];
    \node[every day (month)];
    \node[every weekday];
    \draw[every diag line] (@m.south west) -- (@d.north east);
    \draw[every grid] (@wd|-0,-4*\pgfkeysvalueof{/tikz/grid size})
      -- (O-|@wd);},
  /pgf/calendar/German holidays/.style={
    equals/.list={01-01, 05-01, 10-03, 12-25, 12-26},
    Easter/.list={-2, 1, 39, 50}}, % Karfr, Ostermo, Chr. Himfrt, Pfingstmo
  /pgf/calendar/German maybe holidays/.style={
    equals/.list={01-06, 03-08, 08-15, 10-31, 11-01, 11-23},
    Easter/.list={0, 49, 60}}, % Oster-/Pfingstso, Fronleichnam
\null % cover empty
\foreach \WEEK in {0, ..., 52}{%
  \tikz\draw[every grid] (0,0) grid (\textwidth, \textheight);%
    \coordinate (O) at (0,0);
    \coordinate (@) at (0,\textheight) (@);
        to \STARTDATE+\pgfinteval{\WEEK*7+6},
    ] if (German holidays) [red]
      if (German maybe holidays) [red!75!black];


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .