# View Predicates


Views are not static, they are generated from the model. Any changes in the model are applied immediately and update views.
Two types of predicates define what is visible: element and relationship predicates.

<Aside>
  Views contain elements and their connections (relationships).  
  Connections represent merged relationships - direct between elements and/or those derived from their nested elements.
</Aside>

## Element predicates

Element predicates explicitly define which elements are visible. Each included element brings in its relationships with already visible elements.

```likec4
view {
  // Only backend is visible
  include backend

  // Add frontend to the view 
  // and its relationships with backend
  include frontend 

  // Add authService to the view 
  // and its relationships with visible (backend and frontend)
  include authService

  // Add children of messageBroker,
  // and their relationships among themselves and visible (backend, frontend and authService)
  include messageBroker.*

  // Add all descendants of messageBroker,
  // and their relationships among themselves and visible (backend, frontend and authService)
  include messageBroker.**

  // Exclude emailsQueue and its relationships
  exclude messageBroker.emailsQueue
}
```

<Aside>
  Order is significant; predicates are applied as defined within the view.  
  Excludes apply only to elements/relationships included earlier.
</Aside>

### Combining

Predicates can be combined. The following is the same as example above:

```likec4
view {
  include
    backend,
    frontend,
    authService,
    messageBroker.**

  exclude messageBroker.emailsQueue
}
```

### Wildcard

Wildcard predicates can be used to reference "everything" (but it differs for scoped/unscoped views).  
Consider the following model:

```likec4
model {
  actor customer {
    -> webApp 'uses in browser via HTTPS'
  }
  system cloud {
    container backend {
      component api    
    }
    container ui {
      component webApp {
        -> api 'requests data'
      }
    }
  }
}
views {

  // Unscoped view - wildcard refers to top-level elements
  view {
    include *
    // Visible top-level elements: customer, cloud
    // and derived relationship customer -> cloud
  }

  // Scoped view - wildcard refers to element and its children
  view of cloud.ui {
    include *
    // Visible:
    // - cloud.ui
    // - cloud.ui.webApp
    // - customer
    // - relationship customer -> cloud.ui.webApp
    // - cloud.backend
    // - cloud.ui.webApp -> cloud.backend, derived from cloud.ui.webApp -> cloud.backend.api
  }
}
```

### With overrides

You can modify element properties specifically for the view:

```likec4
// Include the element and override its properties
include cloud.backend with {
  title 'Backend components'
  description '...'
  technology 'Java, Spring'
  icon tech:java
  color amber
  shape browser
  multiple true
}
// Include all nested elements, change color and textSize
include cloud.* with {
  color amber
  textSize small
}  
```

`with` may be used only within `include`.

### With custom navigation

You can define custom navigation and links between views:

```likec4 title="example.c4"

view view2 {
  include *
  include cloud.backend with {
    // navigate to 'view3' on click
    navigateTo view3
  }
}

view view3 {
  include *
  include cloud.backend with {
    // navigate back to 'view2'
    navigateTo view2
  }
}
```

### By element kind or tag

```likec4
// elements by kind
include element.kind != system
exclude element.kind = container

// elements by tag
include element.tag != #V2
exclude element.tag = #next
```

:::caution
These predicates may be deprecated in the future, please consider [`where`](#filter) operator
:::

### Element Selectors

#### Children `.*`

The children selector includes element's children and their relationships with visible elements.

```likec4
include cloud.*

// Same as
include cloud.backend
include cloud.ui
```

#### Descendants `.**`

The descendants selector includes element's descendants **IF** they have a relationship with visible elements.

```likec4
include cloud.**

// Same as
include cloud.backend
include cloud.ui
include cloud.ui.webApp
```

#### Expand `._`

The expand selector includes element's children **IF** they have a relationship with visible elements.
All other children are omitted.

```likec4
include cloud._

// Same as
include cloud
include -> cloud.* ->
```

## Relationship predicates

Relationship predicates include elements only if they have relationships that meet the specified predicate conditions.

### Directed relationships

Include elements if they have **directed** relationships (or their nested elements):

```likec4
// Include customer and cloud:
include customer -> cloud

// Include customer and nested elements of cloud (that have relationships):
include customer -> cloud.*
```

### Any relationship

Include elements if they have any relationships:

```likec4
include customer <-> cloud
```

### Incoming

Include elements if they have incoming relationships from already visible elements.  
Here’s an example based on the model from the [wildcard example](#wildcard):

```likec4 wrap title="incoming predicate.c4"
view {
  // visible element
  include customer

  // include nothing, customer has no relation to backend
  include -> backend

  // add ui,
  // because customer has a relationship with nested ui.webApp
  include -> ui

  // add backend, because visible ui has a relationship to backend
  // derived from ui.webApp -> backend.api
  include -> backend
}

// This view includes customer and ui
view {
  include
    customer,
    -> cloud.*
}
```

:::tip
Relationship predicates are useful for refining your diagrams, allowing you to narrow the scope and focus on specific parts of the system.
:::

### Outgoing

Include elements if only they have outgoing relationships to already visible elements:

```likec4
include customer ->
include cloud.* ->
```

### In/Out

Include nested elements of `cloud`, that have any relationships with visible elements:

```likec4
include -> cloud.* ->
```

### Relationship customization

Relationships can be customized inside view:

```likec4
include
  // Make lines red and solid
  cloud.* <-> amazon.* with {
    color red
    line solid
  },
  // or only directed 
  customer -> cloud.*  with {
    // Override label
    title 'Customer uses cloud'
    navigateTo dynamicview1
  }, 
```
:::tip
Sometimes, connections may have a title `[...]`. This indicates that the connection has been merged from multiple relationships with different titles, and it was impossible to derive a definitive one.  
You can change it:

```likec4
include
  customer -> cloud  with {
    // Change [...] to
    title 'Customer uses cloud'
  }, 
```
:::

:::caution
It is possible to customize relationships with known endpoints only  
(i.e. [directed](#directed-relationships) or [any between](#any-relationship)) 

For example, `* -> *` can be customized (in other words, all relationships on the view), but outgoing `cloud.* ->` can not.
:::

### Relationship navigation

To customize [navigation](/dsl/relationships/#navigate-to) from relationship:

```likec4
include
  webApp -> backend.api with {
    navigateTo dashboardRequestFlow
  }
```

## Filter

`where` operator narrows down results by applying additional conditions:

```likec4
// include only microservices from nested
include cloud.*
  where kind is microservice

// only microservices and not deprecated
include cloud.*
  where
    kind == microservice and // possible to use 'is' or '=='
    tag != #deprecated       // possible to use 'is not' or '!='

// Use logical operators
include cloud.*
  where
    not (kind is microservice or kind is webapp)
    and tag is not #legacy
    and (tag is #v1 or tag is #v2)
```

<br/>

**Relationship predicates**

When `where` is used with element predicates, it is applied to the elements.    
When used with relationship predicates - to the relationships.

```likec4
include
  // only relationships with tag #messaging
  cloud.* <-> amazon.*
    where tag is #messaging,

  // only incoming http-requests
  -> backend
    where kind is http-request
  -[http-request]-> backend
  .http-request backend
```

It is also possible to filter relations by tag or kind of its endpoints.
```likec4
include
  // only relationships outgoing from elements with with tag #next
  cloud.* -> amazon.*
    where source.tag is #next,

  // only incoming relations of elements with kind microservice
  -> *
    where target.kind is microservice
```

<br/>

**Together with `with`**

It is possible to use `where` together with `with`, but `where` should be defined first:

```likec4
include *
  where kind is microservice
  with {
    color amber
  }  
```

<br/>

:::tip
Less verbose and more satisfying results are achieved with `where` in `exclude` predicates.  
For example:

```likec4

// only keep elements tagged with #v1
exclude * where tag is not #v1

// only keep relationships tagged with #commands
exclude * -> * where tag is not #commands

```

Together with [predicate groups](#global-predicate-groups) you may define a "baseline" (includes everything), and then filter out in inherited views.

:::

## Global predicate groups

If you find yourself repeating the same predicates in multiple views, you can define them as global group:

```likec4
global {
  predicateGroup microservices {
    include cloud.*
      where kind is microservice
    exclude *
      where tag is #deprecated
  }
}

views {
  view of newServices {
    include cloud.new.*
    global predicate microservices
  }

  view of newBackendServices {
    // Keep in mind that order is significant
    global predicate microservices
    include cloud.backend.*
  }
}
```

## Groups

It is possible to group elements, and this is rendered as a boundary around them:

```likec4
view {

  group {
    include backend
  }

  // with title
  group 'Frontend' {
    include frontend.*
  }

  // with style
  group 'Service Bus' {
    color amber
    opacity 20%
    border solid

    include messageBroker.*
  }
}
```

Groups can be nested:

```likec4
view {
  group 'Third-parties' {
    group 'Integrations' {      
      group 'Analytics' {}
      group 'Marketing' {}
    }  
    group 'Monitoring' {}
  }
}
```
:::note
Order of predicates is significant. 
<details>
<summary>How element predicates are grouped?</summary>

For element predicates - element stays in first group it was included.

```likec4
group {
  include backend   //wins
  group {
    include backend //ignored
  }
}
group {  
  group {
    include api //wins
  }
  include api   //ignored
}
```
It is possible to change:

```likec4
group {
  include backend   
  group {
    exclude backend 
    include backend //wins
  }
}
```
</details>
<details>
<summary>How relationship predicates are grouped?</summary>

For relationship predicates - the last one "wins":

```likec4 
group {
  include -> backend  
  group {
    include -> backend //wins
  }
}


group {  
  group {
    include -> backend
  }
  include -> backend   //wins
}
```
</details> 
:::

<Aside type="caution" title="Elements hierarchy and Groups">
  Element is included in the group if only there is no parent in the view.  
  This might lead to unexpected results.  
  
  Example:
  ```likec4
  group {
    include cloud
    group 'Backend' {
      include cloud.backend.api // ⛔️ no, will be nested in 'cloud'
    }
  }

  group 'Amazon' {    
    group 'Queues' {
      include amazon.sqs.queue1 // ⛔️ no, will be nested in 'amazon' from below
    }
    include cloud -> amazon
  }
  ```  
</Aside>

## Style predicates

Style predicates define how elements are rendered, and applied in the order they are defined merging with previous ones:

```likec4
view apiApp of internetBankingSystem.apiApplication {

  include *

  // apply to all elements
  style * {
    color muted
    opacity 10%
  }

  // apply only to these elements
  style singlePageApplication, mobileApp {
    color secondary
    size xlarge
  }

  // apply only to nested of apiApplication
  style apiApplication.* {
    color primary
    multiple true
  }

  // apply to apiApplication and nested
  style apiApplication._ {
    color primary
  }

  // apply only to elements with specific tag
  style element.tag = #deprecated {
    color muted
  }

  // apply to elements not tagged
  style element.tag != #deprecated {
    opacity 20%
  }
}
```

:::caution
[`Group`](#groups) does not support nested `style` predicates (yet).
:::

### Shared local styles

Styles can be shared within `views` block (_"local styles"_):

```likec4
views {
  // apply to all views in this block
  style * {
    color muted
    opacity 10%
  }

  view of apiApp {
    include *
    style cloud.web.* {
      color green
    }
  }

  view of mobileApp {
    include *
    style cloud.ui.* {
      color amber
    }    
  }
}

views {
  // Styles from previous block are not applied here
  // ...
}
```

<Aside title="Order">
Styles are applied in the order they are defined.  
First, local styles from `views` block and then from `view`
</Aside>

:::caution
[Overrides](#with-overrides) are always applied last, after all styles
:::


### Shared global styles

Styles can be shared globally.  
Global styles must be named and defined in `global` block:

```likec4  {4,9,15,25,33-34}
global {
  // Format:
  //  style <name> <targets> { ... }
  style mute_all * {
    color muted
    opacity 10%
  }

  style applications
    singlePageApplication._,
    mobileApp._ {
      color secondary
    } 

  style mute_deprecated
    element.tag = #deprecated {
      color muted
    }  
}

views {
  view of singlePageApplication {  
    // Styles are applied in the order they are defined
    // 1. Apply global style
    global style mute_all

    // 2. Then this
    style cloud.* {
      color green
    }

    // 3. and 4.
    global style applications
    global style mute_deprecated    
  }  
}
```

### Shared style groups

Global styles can be grouped:

```likec4 {3,18}
global {
  // Define style group
  styleGroup common_styles {
    style singlePageApplication, mobileApp {
      color secondary
    }
    style element.tag = #deprecated {
      color muted
    }
  }
}

views {  
  view mobileApp of mobileApp {
    include *

    // Apply styles from group
    global style common_styles

    // Override
    style mobileApp {
      color primary
    }
  }
}
```

:::tip
Global styles and groups can be used as `views`-locals:

```likec4
global {
  style mute_all * { color muted }
  styleGroup theme1 { //...
  styleGroup theme2 { //...
}

// All views within this block have styles from 'theme1'
views {
  global style theme1
  view view1 { //... 
}

// All views have 'mute_all' style and all from 'theme2'
views {
  global style mute_all
  global style theme2
  view view2 { //... 
}
```
:::


## Auto-layout

```likec4
view {
  include *
  autoLayout LeftRight 120 110
}
```

Parameters are:
- direction: possible values are `TopBottom` (default), `BottomTop`, `LeftRight`, `RightLeft`.
- rank distance: optional, must be a positive number
- node distance. optional, must be a positive number

<Aside>
Manual changes are supported in VSCode extension, but functionality is limited.  
Your <a href="https://github.com/likec4/likec4/discussions/343" target="_blank">feedback</a> is much appreciated.
</Aside>


## Extend views

Views can be extended to avoid duplication, to create a "baseline" or, for example, "slides" for a presentation:

```likec4
views {

  view view1 {
    include *
  }

  view view2 extends view1 {
    title 'Same as View1, but with more details'

    style * {
      color muted
    }

    include some.backend
  }

  // cascade inheritance
  view view3 extends view2 {
    title 'Same as View2, but with more details'

    include * -> some.backend
  }

}
```

The predicates and style rules of extended views applied after the ones from ancestors.

Extended view also inherits the scope:

```likec4
views {

  view view1 of cloud.backend {
    title 'Backend components'
  }

  view view2 extends view1 {
    include api // ✅ This is OK, references 'cloud.backend.api'
  }

}
```
## Rank constraints

You can keep specific elements on the same horizontal/vertical level (or push them to the beginning/end of the layout)
by adding an explicit `rank` block to the view.
These rank constraints are forwarded to the Graphviz layout engine to achieve the desired layout effects.

```likec4
view checkoutFlow {
  include *

  // keep the API nodes aligned
  rank same {
    cloud.backend.api,
    cloud.backend.billingApi,
  }

  // make customers appear at the beginning of the diagram, exclusive of the elements
  rank source {
    customer
  }

  // render reporting systems at the end, exclusive of the elements
  rank sink {
    analytics,
    dataWarehouse
  }
}
```

- Allowed rank values: `same`, `min`, `max`, `source`, `sink`. If omitted, `same` is assumed.
- Targets are regular `FqnRef`s, so you can reference nested elements just like in other rules. Non-existent or duplicate targets are ignored.
- The constraint only affects elements that actually remain in the computed view. If a predicate later removes an element, it also disappears from the rank block.
- Rank rules participate in manual tiling of compound nodes as well, so authored constraints combine with the automatic layout instead of fighting it.

Use rank constraints sparingly—they are most helpful for anchoring critical columns/rows
(e.g., ingress vs. egress nodes, semantic grouping in lieu of container) to achieve better layout.