# Create Advanced Layouts

## Content

Use a custom `SchedulerDefinition` when a built-in view does not match the way users need to scan time and resource data. A definition places ordered time and resource bindings on the row and column axes.

## Define a custom layout

| Binding type | Defines | Typical values | Required properties | Optional properties |
| ------------ | ------- | -------------- | ------------------- | ------------------- |
| Time | Date or time slots | `Hour`, `Day`, `DayOfWeek`, `DayOfMonth` | `type`, `unit` | `visible` callback |
| Resource | Groups from `scheduler.resources` | `roomId`, `teamId` | `type`, `fieldExpr` | None |

Binding order determines which binding becomes the outer group. The `fieldExpr` of a resource binding must match a configured resource descriptor.

```ts
const definition: wjScheduler.SchedulerDefinition = {
  key: 'weekByRoom',
  rows: {
    bindings: [{
      type: wjScheduler.SchedulerAxisBindingType.Time,
      unit: wjScheduler.SchedulerTimeUnit.Hour,
    }],
  },
  columns: {
    bindings: [
      { type: wjScheduler.SchedulerAxisBindingType.Time, unit: wjScheduler.SchedulerTimeUnit.DayOfWeek },
      { type: wjScheduler.SchedulerAxisBindingType.Resource, fieldExpr: 'roomId' },
    ],
  },
  cellSemantic: wjScheduler.SchedulerCellSemantic.Timed,
};

scheduler.definition = definition;
```

![image](https://docapp.mescius.io/DOCUMENT_SITE_LINK_PREFIX_HERE/document-site-files/images/3c7113e2-10b3-45ed-8f3b-9fb1e0af2b74/image-20260909.9362d2.png?width=800)

## Check the layout before rendering

Use `planSchedulerProjection` when views are assembled dynamically or supplied by configuration. It analyzes the definition without changing Scheduler state.

```ts
const plan = wjScheduler.planSchedulerProjection(definition);
console.log(plan.slotAxis);
console.log(plan.integrity.level);
console.log(plan.integrity.reasons);
```

`plan.integrity.level` reports whether the definition can be rendered as written.

| Integrity level | Meaning | Result |
| --------------- | ------- | ------ |
| `faithful` | Axis structure and binding order can be preserved. | Renders as configured. |
| `lossy` | The view can render, but part of the requested order is normalized. | Renders with normalized grouping. |
| `unsupported` | The definition is ambiguous or cannot be projected. | Assigning it throws an error and leaves the previously active definition unchanged. |

When Scheduler cannot keep the declared order, it adjusts the layout and reports why in `plan.integrity.reasons`. The message may say that a binding is normalized or rendered as an outer grouping, which means Scheduler placed it in a group around the time axis.

## Timed definition rules

Timed layouts position events by their time range and require one continuous hour axis.

| Rule | Valid configuration | Invalid or normalized configuration |
| ---- | ------------------- | ----------------------------------- |
| Hour axis | Exactly one `time:hour` binding | Missing or repeated `time:hour` is unsupported |
| Hour binding placement | The hour binding is alone on its row or column axis | Sharing the axis with another binding is `lossy`; Scheduler separates the other bindings into groups instead of preserving the declared mixed order. |
| Resource identity | Each resource field appears once across both axes | Repeating the same resource field is unsupported |
| Calendar context | Include a day-level binding when sections need concrete dates | `weekOfMonth` + `hour` without a day-level binding is unsupported |

In a Timed definition, `time:hour` must provide one continuous time axis. Keep it as the only binding on its axis and place other bindings on the opposite axis. Use `planSchedulerProjection` to identify configurations that Scheduler must normalize.

## Summary definition rules

Summary layouts arrange fixed-size items inside cells and do not require a `time:hour` binding.

| Rule | Behavior |
| ---- | -------- |
| Repeated time unit | Unsupported when the same unit appears more than once |
| Repeated resource field | Unsupported when the same resource field appears more than once |
| Resize | Not supported for summary items |
| Single lane | A timed definition with one `time:hour` binding and no bindings on the opposite axis renders one lane for displayDate. |

## Handle unsupported definitions

Validate a custom definition before assigning it and provide a supported fallback when configuration is user-supplied. Assignment can also be protected with `try/catch` when definitions are assembled dynamically.

```ts
const plan = wjScheduler.planSchedulerProjection(definition);

if (plan.integrity.level === 'unsupported') {
  scheduler.definition = wjScheduler.createSchedulerDefinitionPreset(
    wjScheduler.SchedulerBuiltInViewItem.Week
  );
} else {
  scheduler.definition = definition;
}
```

Keep definitions minimal while testing a new layout: start with one time binding, add resource bindings one at a time, and verify the resulting grouping before introducing additional axes.