You can use this page to identify the Turnkey web-client layout wrappers and write CSS that targets the whole application, a ViewModel, the sidebar, the ViewModel content area, or validation messages.
Turnkey renders a consistent page hierarchy around your content. The wrapper IDs described here are useful when you need to change application-level layout behavior, such as hiding a sidebar for one ViewModel or adjusting the scrolling area. For component-level styling and theming, use Documentation:Turnkey Styling, Documentation:CSS BEM, and Documentation:MDriven Turnkey theming instead.
Layout hierarchy
The following hierarchy describes the main containers in the Turnkey web client. IDs are CSS selectors; prefix an ID with # in a CSS selector. Classes are prefixed with ..
#bodyWrapper
#globalNavWrapper
#globalContentWrapper
#flexLayoutWrapper
#contentWrapper
#sidebarWrapper
#sidebar
#viewmodelWrapper
#viewmodelSection
#validationMessageWrapper
#validationMessages
| Wrapper or area | Purpose | Notes |
|---|---|---|
#bodyWrapper
|
Wraps the web client body. | Use it when a rule must apply to the overall application layout. |
#globalNavWrapper
|
Contains the global navigation, also called the top or main menu. | The navigation is MVC-generated and modified by AngularJS code. |
#globalContentWrapper
|
Contains the page content below the global navigation. | A non-ViewModel page, such as login, starts directly in this wrapper. |
#flexLayoutWrapper
|
Restores the margin below the navigation and provides the full-height layout area. | For AngularJS, this is where the AngularJS application starts, with ng-app and ng-view. For MVC posting forms, the <form> and <fieldset> are directly below this wrapper.
|
#contentWrapper
|
Holds the sidebar and the ViewModel area. | In AngularJS, server-generated HTML is injected here and data-bound on the client. In MVC, it is part of the complete server-rendered page. |
#sidebarWrapper and #sidebar
|
Hold the sidebar content. | The wrapper supports non-flex handling, including scrollbar and manual-height behavior for Safari and Edge. The sidebar takes the space it needs and scrolls vertically when necessary. |
#viewmodelWrapper
|
Wraps the ViewModel display area. | Like the sidebar wrapper, it supports non-flex handling with scrollbars and manual-height behavior for Safari and Edge. |
#viewmodelSection
|
Contains the rendered ViewModel. | It can contain one scrolling content block or a splitter-based segmented layout. |
#validationMessageWrapper
|
Wraps validation feedback. | Located alongside the main content structure. |
#validationMessages
|
Formats the displayed validation information, warnings, and errors. | Messages are AngularJS data-bound. |
Understand ViewModel scrolling and split areas
#viewmodelSection can be rendered in two general ways:
- One content block. The ViewModel is one ordinary block. It provides scrolling in both directions, and that block handles all scrolling.
- A segmented layout. A ViewModel with splitters can render two, three, or more grid-box segments in the X and/or Y direction. The first and last segments use the space they need. Middle segments scroll in both directions.
The vmGridBox* classes are present only when the design includes splitters. Do not base ordinary ViewModel styling on these classes unless the ViewModel is intentionally designed with splitters.
Target one ViewModel
Turnkey adds a CSS class named after the ViewModel high in the HTML hierarchy. Use that class to scope a rule to one view without changing the same element in other views.
For example, if the ViewModel is named WorkBoard, hide the sidebar only while that ViewModel is active:
.WorkBoard #sidebar {
visibility: hidden;
}
This selector does not hide the sidebar on other views because .WorkBoard limits the rule to the WorkBoard ViewModel.
Use this pattern whenever a layout change belongs to a specific ViewModel. For example, you can adjust spacing in one ViewModel's content section:
.WorkBoard #viewmodelSection {
padding: 1rem;
}
Keep selectors scoped where possible. A rule such as #sidebar { ... } affects every ViewModel that has a sidebar.
Style controls by control type
Turnkey adds a CSS class to the outer div that encloses a control and its label. This gives you a generic control-type hook without having to name each individual control.
The control-type classes originate from the following control types:
| Control type | CSS class |
|---|---|
| Static text | ctStaticText
|
| Image | ctImage
|
| Text edit | ctTextEdit
|
| Date picker | ctDatePicker
|
| Checkbox | ctCheckbox
|
| Combobox | ctCombobox
|
| Button | ctButton
|
| Grid | ctGrid
|
| Groupbox | ctGroupbox
|
| File control | ctFile
|
| Link | ctLink
|
| Text area | ctTextArea
|
| Number edit | ctNumberEdit
|
| Float number edit | ctFloatNumberEdit
|
For example, target the outer wrapper of all text-edit controls:
.ctTextEdit {
margin-bottom: 0.5rem;
}
If a control has no label in the ViewModel design, its enclosing div also receives the NoLabel class. This lets you handle labelled and unlabelled controls differently:
.ctTextEdit.NoLabel {
margin-top: 0.5rem;
}
When the ViewModel uses CSS Grid, this enclosing div is the item placed in the CSS Grid. When it uses Bootstrap layout, it is the bootstrapped div placed in the 12-column layout.
Choose the right styling mechanism
Use the smallest-scope mechanism that matches the change you need.
| Need | Use | Example |
|---|---|---|
| Change an application wrapper, sidebar, scrolling area, or validation-message area | The layout IDs on this page | .WorkBoard #sidebar { visibility: hidden; }
|
| Add a class to a particular control from MDriven Designer | The control's Style ref and CSS rules | Add order-summary as Style ref, then target .order-summary in CSS.
|
| Style a generated Turnkey control and its label or native input | Turnkey BEM classes | Target a text field label with the appropriate BEM element selector. |
| Change shared colors, sizes, fonts, or other theme values | Documentation:MDriven Turnkey theming or Documentation:Tkusercss | Set a CSS custom property in tkusercss.css rather than repeating color values in many selectors.
|
| Organize controls responsively as nested layout blocks | Documentation:PlacingContainer | Use a column-direction container to stack fields and fill horizontally. |
| Style rows, columns, or cells in a grid from ViewModel data | HowTos:Styling and CSS for Bootstrap, Angular and MVC | Provide a CssClass attribute for a row, or ColumnName_CssClass for a cell.
|
Work with CSS Grid and PlacingContainers
Turnkey uses CSS Grid for application layout unless your ViewModel uses PlacingContainers. A PlacingContainer uses FlexBox as its core layout mechanism.
This distinction matters when you change layout:
- Use the layout wrappers on this page for the outer Turnkey page structure.
- Use the ViewModel's grid placement for the default grid-based arrangement of controls.
- Use PlacingContainers when you need nested, box-in-box layout behavior. A container with direction Column fills horizontally and stacks its children vertically; direction Row fills vertically and places children horizontally.
- Plan responsive groups as meaningful blocks. For example, group an image and its details in a container, then configure wrapping when the pair must move onto separate lines on a narrow display.
Do not use global wrapper CSS to compensate for a ViewModel layout that should instead be expressed with a PlacingContainer or the ViewModel's grid design.
Keep custom CSS maintainable
- Start with theme settings or CSS custom properties for shared colors, measures, and typography. See Documentation:MDriven Turnkey theming and Documentation:Theme as data.
- Use BEM block, element, and modifier classes for component styling. Turnkey treats style references added in MDriven Designer as modifiers; see Documentation:CSS BEM.
- Scope exceptional layout rules with the ViewModel class, as in
.WorkBoard #sidebar. - Target stable wrapper IDs only when the change concerns the corresponding page area.
- Test a ViewModel with and without splitters before relying on
vmGridBox*classes.
