🚀 Welcome to MDriven Learn –  MDriven is now on Discord!  Don’t miss the latest Release Notes.
Layout and CSS
This page was created by Lars.olofsson on 2017-07-22. Last edited by Wikiadmin on 2026-07-29.

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

  1. Start with theme settings or CSS custom properties for shared colors, measures, and typography. See Documentation:MDriven Turnkey theming and Documentation:Theme as data.
  2. Use BEM block, element, and modifier classes for component styling. Turnkey treats style references added in MDriven Designer as modifiers; see Documentation:CSS BEM.
  3. Scope exceptional layout rules with the ViewModel class, as in .WorkBoard #sidebar.
  4. Target stable wrapper IDs only when the change concerns the corresponding page area.
  5. Test a ViewModel with and without splitters before relying on vmGridBox* classes.

See also