Checklist, color and time fields

Three field types on a table of sessions: a checklist with a progress bar and an editor to tick, add and reorder items, a color with a swatch and the 40-color palette, and a time of day typed as 9:30 am or 14:05 and shown on a 12 or 24 hour clock. (requires @svgrid/enterprise)

A live, editable Svelte 5 data grid example from the SvGrid gallery (Base). See the SvGrid documentation for the full API.

About this example

Checklist, color and time of day fields in an SvGrid Base, in Svelte 5. A checklist cell shows how many items are done and opens an editor to tick, add, rename, reorder and delete them; a color cell shows a swatch and hex code; a time of day is stored as HH:MM and typed as 9:30 am, 14:05 or 2pm.

Three field types on a table of conference sessions.

Prep is a checklist: the cell shows how many items are done and a bar. Click it to tick, add, rename, drag or delete items. It sorts by the share done, and the second view filters for sessions not complete yet.

Track is a color: a swatch and the hex code. The editor offers the 40 option colors and a box for a hex code; a paste reads #rgb, #rrggbb, rgb() or a CSS name such as "navy".

Starts and Ends are times of day with no date, stored as 'HH:MM'. Starts shows a 12-hour clock, Ends a 24-hour one. Type "9:30 am", "14:05" or "2pm"; Up and Down in the editor move by 15 minutes.

Imports, features and API used

Imports: @svgrid/grid, @svgrid/enterprise/base, ../shared/base-people

Columns: session (Session), track (Track), starts (Starts), ends (Ends), prep (Prep), host (Host)

Frequently asked questions

How is a checklist stored?

As an array of items, each { id, text, done }, in the order they show. A copy writes them as text, "[x] Done item [ ] Open item", and a paste or a CSV import reads that back. It sorts by the share of items done and filters by is complete, is not complete, % done or an item's text.

Which colors can be pasted into a color field?

#rgb, #rrggbb, rgb(r, g, b) and common CSS names such as red, navy or teal. The value is stored as lower case #rrggbb. Text that is not one of those (a name not on the list, hsl(), a color with alpha) leaves the cell as it was.

Why is a time of day stored as text and not as seconds?

HH:MM on a 24-hour clock reads the same in JSON, a CSV and a SQL time column, sorts in time order as plain text, and cannot be mistaken for a duration, which the base stores as seconds. The field's 12 or 24 hour setting only changes what the cell shows.

Which license does it need?

SvGrid Base is part of the Suite edition of @svgrid/enterprise. Without a key it runs with a watermark, so it can be evaluated as is.

Related documentation

Related articles

  • A Live Svelte Data Grid with Firebase Firestore - Wire Firestore onSnapshot to SvGrid in Svelte 5 - reactive listeners, query-driven sort and filter, cursor pagination, and the subtle cleanup detail most implementations get wrong.
  • A Svelte Data Grid with PocketBase - Wire SvGrid to PocketBase for server-side paging, sorting, and filtering via getList, plus live row updates through PocketBase realtime subscriptions.
  • Throttling Live Grid Updates to Animation Frames - High-frequency WebSocket feeds will wreck grid performance if you apply every message immediately. One rAF buffer and a Map coalescer cuts thousands of renders down to 60 per second.

Source code (715-base-checklist-color-time.svelte)

<script lang="ts">
  /**
   * 715. SvGrid Base: checklist, color and time of day fields
   * ----------------------------------------------------------
   * Three field types on a table of conference sessions.
   *
   * Prep is a checklist: the cell shows how many items are done and a bar.
   * Click it to tick, add, rename, drag or delete items. It sorts by the
   * share done, and the second view filters for sessions not complete yet.
   *
   * Track is a color: a swatch and the hex code. The editor offers the 40
   * option colors and a box for a hex code; a paste reads #rgb, #rrggbb,
   * rgb() or a CSS name such as "navy".
   *
   * Starts and Ends are times of day with no date, stored as 'HH:MM'. Starts
   * shows a 12-hour clock, Ends a 24-hour one. Type "9:30 am", "14:05" or
   * "2pm"; Up and Down in the editor move by 15 minutes.
   */
  import { SvToaster } from '@svgrid/grid'
  import { SvBase, enableBase, type BaseTable } from '@svgrid/enterprise/base'
  import { usePeople } from '../shared/base-people'

  enableBase()
  usePeople()

  const steps = (done: number, ...names: string[]) => names.map((text, i) => ({ id: `s${i}`, text, done: i < done }))
  const SESSIONS: Array<[string, string, string, string, string, ReturnType<typeof steps>]> = [
    ['Opening keynote', '#2d7ff9', '09:00', '09:45', 'u1', steps(4, 'Slides final', 'Speaker briefed', 'Mic check', 'Livestream link')],
    ['Runes in practice', '#20c933', '10:00', '10:40', 'u3', steps(2, 'Slides final', 'Demo repo tagged', 'Mic check')],
    ['Grids at a million rows', '#8b46ff', '10:00', '10:40', 'u4', steps(1, 'Slides final', 'Benchmark rerun', 'Laptop on venue wifi', 'Mic check')],
    ['Lunch', '#fcb400', '12:00', '13:00', 'u6', steps(1, 'Dietary list sent', 'Count confirmed')],
    ['Forms without a library', '#20c933', '13:15', '13:55', 'u2', steps(0, 'Slides final', 'Mic check')],
    ['Accessible tables', '#ff6f2c', '14:00', '14:40', 'u5', steps(3, 'Slides final', 'Screen reader demo', 'Captions file')],
    ['Shipping a design system', '#8b46ff', '15:30', '16:10', 'u7', steps(1, 'Slides final', 'Figma file shared', 'Mic check')],
    ['Closing panel', '#2d7ff9', '16:30', '17:15', 'u8', steps(0, 'Panelists confirmed', 'Questions collected', 'Mic check')],
  ]
  const data = SESSIONS.map(([session, track, starts, ends, host, prep], i) => ({ id: `e${i + 1}`, session, track, starts, ends, host, prep }))

  let tables = $state.raw<BaseTable[]>([
    {
      id: 'conf-sessions',
      name: 'Sessions',
      primaryField: 'session',
      data,
      columns: [
        { field: 'session', header: 'Session', width: 240, fieldType: 'text' },
        { field: 'track', header: 'Track', width: 130, fieldType: 'color' },
        { field: 'starts', header: 'Starts', width: 110, fieldType: 'timeOfDay', fieldProps: { timeFormat: '12hour' } },
        { field: 'ends', header: 'Ends', width: 100, fieldType: 'timeOfDay', fieldProps: { timeFormat: '24hour' } },
        { field: 'prep', header: 'Prep', width: 170, fieldType: 'checklist' },
        { field: 'host', header: 'Host', width: 160, fieldType: 'user' },
      ],
      views: [
        { id: 'agenda', name: 'Agenda', type: 'grid', state: { sorting: [{ id: 'starts', desc: false }] } },
        {
          id: 'open-prep',
          name: 'Prep not done',
          type: 'grid',
          state: {
            sorting: [{ id: 'prep', desc: false }],
            advancedFilter: { kind: 'fieldFilter', conjunction: 'and', conditions: [{ column: 'prep', kind: 'checklist', op: 'notAllDone' }] },
          },
        },
      ],
      props: { rowAdder: { label: 'Add session' } },
    },
  ])
</script>

<section class="base-demo">
  <p class="base-demo-tip">
    Click a Prep cell to tick or add items, double-click a Track to pick a color, or select a Starts cell and type <kbd>2pm</kbd>.
    Copy a Prep cell and paste it into another: it copies as <code>[x] item [ ] item</code>.
  </p>
  <SvBase
    bind:tables
    editable
    sortable
    showRowNumbers
    expandRows
    rowNumberWidth={64}
    showRowSelection={false}
    rowHeight={40}
    containerHeight="100%"
    columnAdder
    fieldMenu
  />
  <SvToaster />
</section>

<style>
  .base-demo { display: flex; flex-direction: column; flex: 1; min-height: 480px; height: 100%; gap: 10px; }
  .base-demo-tip { margin: 0; font-size: 13px; line-height: 1.5; color: var(--sg-muted, #64748b); }
  .base-demo-tip kbd,
  .base-demo-tip code {
    padding: 1px 5px; font: inherit; font-size: 12px; border-radius: 4px;
    border: 1px solid var(--sg-border, #e2e8f0); background: color-mix(in srgb, var(--sg-fg, #0f172a) 7%, transparent); color: var(--sg-fg, #0f172a);
  }
</style>

View this example on GitHub

More Base examples

  • Project tracker - A project tracker, ready to use: Tasks and Milestones as two linked tables. Tasks have status, tags, assignee, dates, estimate, progress, budget and files; each milestone lists its tasks with their progress and budget. Views for all tasks, the board by status, due dates on a calendar, a gallery and a request form. Automations close finished tasks, start work from a button and flag overdue ones.
  • Content calendar - An editorial content calendar, ready to use: Posts and Campaigns as two linked tables. Posts have stage, channels, author, publish date, cover and brief. Views for the plan, the pipeline as a Kanban, the publishing calendar, a wall of covers and a pitch form.
  • Sales CRM - A sales CRM, ready to use: Deals, Accounts and Contacts as three linked tables. Link a deal to an account and the account lists it. Views for all deals, the pipeline as a Kanban, the closing calendar, open deals by owner and a new-lead form.
  • Product roadmap - A product roadmap, ready to use: Features and customer Feedback as two linked tables. Features have quarter, status, teams, lead, impact, effort and votes. Views for the roadmap grouped by quarter, a status board, a timeline, the work in progress now and a request form.
  • Hiring tracker - A hiring tracker, ready to use: Candidates and Roles as two linked tables. Candidates have photo, role, stage, recruiter, rating, interview date and resume; each role lists its candidates. Views for the pipeline as a Kanban, all candidates, a gallery of faces, interviews and an application form.