Board Plugin

The Board plugin adds a task board view to DayFlow. It lays out the calendar's own tasks (kind: 'task') in columns by status, priority or assignee. Cards move between columns with drag and drop, and every change is saved through the regular calendar events and callbacks, so the board adds no second data store.

Try it in the interactive demo.

Installation

npm install @dayflow/plugin-board

Usage

The board is a view: register it in views next to your calendar views. It needs enableTasks: true, and taskMembers adds the people tasks can be assigned to.

import {
  DayFlowCalendar,
  createMonthView,
  useCalendarApp,
} from '@dayflow/react';
import { createBoardView } from '@dayflow/plugin-board';
import '@dayflow/core/dist/styles.css';
import '@dayflow/plugin-board/styles.css';

// Create the view once so its board state survives re-renders.
const board = createBoardView();

export function TaskCalendar() {
  const calendar = useCalendarApp({
    views: [createMonthView(), board],
    enableTasks: true,
    taskMembers: [
      { id: 'ava', name: 'Ava Chen' },
      { id: 'leo', name: 'Leo Martin', avatarUrl: '/leo.png' },
    ],
    callbacks: {
      onEventUpdate: event => saveEvent(event),
    },
  });

  return <DayFlowCalendar calendar={calendar} />;
}

saveEvent stands for your own persistence function. Board then appears in the view switcher.

Task data

Columns, priority and assignees are task fields, so the board, the calendar views and the task editor all read and write the same values. See Statuses and assignees for the taskStatuses and taskMembers options.

FieldMeaning
task.statusColumn ID from taskStatuses (default todo, in-progress, done)
task.assigneeIdsMember IDs from taskMembers
task.priority'none' | 'low' | 'medium' | 'high'
task.completedThe checkbox; kept in sync with completed statuses
startDue date. New tasks from the board are due today, all-day
  • When a status is completed: true, moving a card into it completes the task and moving it out reopens it. Completing a task elsewhere moves it to the first completed status.
  • Without a completed status, the checkbox is independent of the columns.
  • In assignee grouping a card belongs to its first assignee. Moving it swaps that assignee and keeps the others; Unassigned clears them all.
  • The board respects calendar visibility and the calendar's read-only settings.

Using the board

  • Move cards: drag cards between columns to change status, priority or assignee, or within a column to reorder. Focused cards move with Alt + arrow keys or Alt + Home/End.
  • Open a card: click it to edit the title, column, priority, assignees, due date and notes in the task editor.
  • Add tasks: + in a column header or New task at the bottom of a column adds a task with that column's status, priority or assignee.
  • Edit columns: click a status column's title to rename it; its ⋯ menu renames, recolors or deletes it. Deleting a column asks whether to merge its tasks into another column or delete them. Add column adds a new status.
  • Reorder columns: drag a column header, or press Alt + Left/Right on a focused header.
  • Group and filter: Group by switches between status, priority and assignee. Click member avatars to show only their tasks.

Status column edits call app.setTaskStatuses and the onTaskStatusesChange callback, so persist them there.

Options

OptionTypeDefaultDescription
label, titlestring'Board'View switcher label; accessible name of the board
groupBy'status' | 'priority' | 'assignee''status'Initial grouping
allowStatusEditbooleantrueAdd, rename, recolor and delete status columns
allowCreatebooleantrueShow New task; also needs write permission
initialStateBoardViewState-Saved grouping, column and card order, assignee filter
messagesPartial<BoardMessages>-Override labels (English and Chinese are built in)
columnWidthnumber-Column width in px, minimum 220
showDescriptionbooleantrueShow task notes on cards
cardFields{ priority?, description?, due?, assignees? }-Set a field to false to hide it on cards
cardClassNamestring | (args) => string-Class names for a card
cardStyleobject | (args) => object-Inline styles for a card
renderCard({ event, app, open }) => ComponentChildren-Extra Preact content below the card title

cardClassName and cardStyle receive { event, app, groupId, groupBy }.

Callbacks

CallbackWhen
onTaskMoveBefore a drag or keyboard move: { event, from, to, groupBy }. Return false to cancel
onTaskCreateBefore New task adds a task. Return a changed draft, or false
onColumnDeleteAfter a column delete is confirmed. Return false to cancel
onCardClickA card is clicked or opened with Enter. Return false to keep the editor closed
onViewStateChangeGrouping, column or card order or the filter changed. Persist the state here
onErrorA task save or state notification failed

Task data changes still reach the calendar callbacks (onEventCreate, onEventUpdate, onEventDelete, onTaskStatusesChange).

Saving the board layout

Grouping, column order, card order and the assignee filter are presentation state. They never change your tasks; onViewStateChange reports them, and initialState restores them:

const board = createBoardView({
  initialState:
    JSON.parse(localStorage.getItem('board') ?? 'null') ?? undefined,
  onViewStateChange: state =>
    localStorage.setItem('board', JSON.stringify(state)),
});

board.getState(app) and board.setState(app, state) read and replace the state from code. Keep the view factory stable: separate calendars keep separate state even when they share one factory.

Styling cards

Cards read CSS custom properties, which can be set on .df-board, a column or a single card:

PropertyDefault
--df-board-card-bgvar(--df-color-card)
--df-board-card-fginherited
--df-board-card-radius0.5rem
--df-board-card-padding0.625rem 0.75rem 0.6875rem
--df-board-card-gap0.375rem
--df-board-card-shadow, --df-board-card-shadow-hoverhairline ring and soft shadow
--df-board-card-title-size, --df-board-card-title-weight0.875rem, 500

Each card also carries data-priority, data-group, data-calendar, data-completed and data-due (overdue, today or upcoming):

.df-board-card[data-due='overdue'] {
  box-shadow: inset 3px 0 #ef4444;
}

Limitations

  • The board shows the tasks loaded into the calendar, across all dates. If you load events by visible range, load the board's tasks too.
  • Every task has a due date; undated tasks, labels and subtasks are not supported yet.
  • renderCard returns Preact content. Framework-native card slots are not available yet.

On this page