Time Grid
Draw time ranges over a typical week with the mouse, the keyboard or a finger. Built for dayparts, opening hours and availability.
Basic Usage
Drag a rectangle to fill it: Monday to Friday, 09:00 to 18:00 in one stroke. Starting on a filled cell erases instead,
and a click on a day or an hour fills or clears its whole line. The value is a list of `day`, `start` and `end` ranges,
the same shape as `time-picker range multiple` with a `day` key.
12a
1a
2a
3a
4a
5a
6a
7a
8a
9a
10a
11a
12p
1p
2p
3p
4p
5p
6p
7p
8p
9p
10p
11p
Sun
Mon
Tue
Wed
Thu
Fri
Sat
[
{
"day": "mon",
"start": "09:00",
"end": "12:00"
},
{
"day": "mon",
"start": "14:00",
"end": "18:00"
},
{
"day": "tue",
"start": "09:00",
"end": "12:00"
},
{
"day": "tue",
"start": "14:00",
"end": "18:00"
},
{
"day": "wed",
"start": "09:00",
"end": "12:00"
},
{
"day": "wed",
"start": "14:00",
"end": "18:00"
},
{
"day": "thu",
"start": "09:00",
"end": "12:00"
},
{
"day": "thu",
"start": "14:00",
"end": "18:00"
},
{
"day": "fri",
"start": "09:00",
"end": "12:00"
},
{
"day": "fri",
"start": "14:00",
"end": "18:00"
}
]
<neura::time-grid wire:model.live="dayparts" />
<!-- $dayparts will be [['day' => 'mon', 'start' => '09:00', 'end' => '12:00'], …] -->
Deferred Binding
Without `.live`, painting stays in the browser and the value travels with the next request. Renders of the page leave the painted cells alone.
8a
9a
10a
11a
12p
1p
2p
3p
4p
5p
6p
7p
Sun
Mon
Tue
Wed
Thu
Fri
Sat
[]
<neura::time-grid wire:model="availability" start="08:00" end="20:00" />
<neura::button wire:click="save">Save</neura::button>
Step and Hours
`step` sets the minutes per cell (60, 30 or 15), `start` and `end` the hours shown. Ranges outside them, or off the step, are kept as they are until their own cells are touched.
8a
9a
10a
11a
12p
1p
2p
3p
4p
5p
6p
7p
Sun
Mon
Tue
Wed
Thu
Fri
Sat
<neura::time-grid :step="30" start="08:00" end="20:00" wire:model="shifts" />
Orientation
Days run down the grid in `rows` and across it in `columns`. The default, `auto`, turns days into columns past 24 cells a day, so quarter hours stay readable.
Sun
Mon
Tue
Wed
Thu
Fri
Sat
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
<neura::time-grid orientation="columns" :step="30" start="08:00" end="18:00" />
Custom Columns
`days` takes weekday keys (`['mon', 'tue', 'wed', 'thu', 'fri']`), kept in week order from `first-day`, or any list of keys and labels: rooms, people, channels. With a free list the value uses `column` instead of `day`.
8a
9a
10a
11a
12p
1p
2p
3p
4p
5p
6p
7p
Room A
Room B
Studio
<neura::time-grid :days="['a' => 'Room A', 'b' => 'Room B', 'studio' => 'Studio']" wire:model="bookings" />
<!-- $bookings will be [['column' => 'a', 'start' => '09:00', 'end' => '11:00'], …] -->
<neura::time-grid :days="['mon', 'tue', 'wed', 'thu', 'fri']" first-day="mon" />
Paint Mode
`selection="paint"` fills every cell the pointer passes over, for shapes a rectangle can't draw.
12a
1a
2a
3a
4a
5a
6a
7a
8a
9a
10a
11a
12p
1p
2p
3p
4p
5p
6p
7p
8p
9p
10p
11p
Sun
Mon
Tue
Wed
Thu
Fri
Sat
<neura::time-grid selection="paint" wire:model="slots" />
Levels
`levels` adds brushes, picked above the grid. Each takes a design-system colour (`primary`, `warning`, `success-600`…); the first defaults to the configured colour. Every range then carries its `level`.
12a
1a
2a
3a
4a
5a
6a
7a
8a
9a
10a
11a
12p
1p
2p
3p
4p
5p
6p
7p
8p
9p
10p
11p
Sun
Mon
Tue
Wed
Thu
Fri
Sat
<neura::time-grid
:levels="['on' => 'Live', 'boost' => ['label' => 'Boosted', 'color' => 'warning']]"
wire:model="dayparts"
/>
<!-- [['day' => 'fri', 'start' => '18:00', 'end' => '23:00', 'level' => 'boost'], …] -->
Blocked Slots
`disabled` takes ranges in the value's shape; their cells are hatched over whatever they hold, and a rectangle skips them. `disabled` alone locks the whole grid and keeps its value in view.
8a
9a
10a
11a
12p
1p
2p
3p
4p
5p
6p
7p
Sun
Mon
Tue
Wed
Thu
Fri
Sat
<neura::time-grid :disabled="[
['day' => 'sat', 'start' => '00:00', 'end' => '24:00'],
['day' => 'mon', 'start' => '12:00', 'end' => '14:00'],
]" />
Read Only
`readonly` shows a week without letting anyone change it, and drops the toolbar.
6a
7a
8a
9a
10a
11a
12p
1p
2p
3p
4p
5p
6p
7p
8p
9p
Sun
Mon
Tue
Wed
Thu
Fri
Sat
<neura::time-grid readonly :value="$openingHours" />
Value Formats
`format="days"` groups the ranges by column, listing every column shown even when empty. Times are always 24-hour `HH:mm`, with `24:00` for the end of the day, whatever clock is shown.
Either shape is read coming in, as are `HH:mm:ss` times; overlapping ranges are merged.
8a
9a
10a
11a
12p
1p
2p
3p
4p
5p
Mon
Tue
Wed
{
"mon": [
{
"start": "09:00",
"end": "17:00"
}
],
"wed": [
{
"start": "09:00",
"end": "12:00"
}
]
}
<neura::time-grid format="days" wire:model="week" />
<!-- $week will be ['mon' => [['start' => '09:00', 'end' => '17:00']], 'tue' => [], …] -->
Size and Style
`size` sets the header text, the cell height and the gap; `rounded` the frame's corners; `color` the first level.
Without them, the grid follows `config('neura-kit.time-grid')`, whose `rounded` defaults to the global style.
8a
9a
10a
11a
12p
1p
2p
3p
4p
5p
Mon
Tue
Wed
8a
9a
10a
11a
12p
1p
2p
3p
4p
5p
Mon
Tue
Wed
<neura::time-grid size="sm" />
<neura::time-grid size="lg" rounded="xl" color="success" />
// config/neura-kit.php
'time-grid' => Config::timeGrid([
'default' => ['size' => 'sm', 'color' => 'success'],
]),
Keyboard and Touch
Arrow keys move between cells, Shift with the arrows draws a rectangle and Space or Enter applies it (or toggles one cell); Escape drops it.
On touch screens the page still scrolls over the grid: a tap toggles a cell, a long press then a drag selects.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| days | array | the 7 weekdays | Weekday keys, or key => label for a free list of columns |
| firstDay | mon|sun|… | locale | First weekday shown |
| start / end | string|int | '00:00' / '24:00' | Hours shown (8, 08:00 or 08:00:00), snapped to the step |
| step | 60|30|15 | 60 | Minutes per cell |
| orientation | auto|rows|columns | auto | Days down the grid (rows) or across it (columns); auto switches past 24 cells a day |
| selection | rectangle|paint | rectangle | Drag a rectangle, or paint cell by cell |
| levels | array | one level | Brushes: key => label, or key => ['label' => …, 'color' => …] |
| disabled | array|bool | [] | Blocked ranges in the value's shape, or true to lock the whole grid |
| readonly | boolean | false | Display only, no toolbar |
| format | ranges|days | ranges | A list of ranges, or ranges grouped by column |
| hourCycle | 12|24|null | null | Clock of the labels; null follows the locale |
| locale | string | 'en' | Weekday names, first day and the default clock |
| clearable | boolean | true | Show the Clear all button |
| name | string | null | Hidden inputs for plain form posts (name[0][day], name[0][start] …) |
| size | sm|md|lg | config: md | Header text, cell height and gap (pack: TimeGrid\Size) |
| rounded | string | config: global | Corners of the frame |
| color | string | config: primary | Colour of the first level |