# Skip Logic {#skip-logic}


Skip Logic controls **whether a question is shown**. A question with skip logic
only appears when its conditions are met. This is different from
[Validation](/user-manual/validation.md), which controls whether an *entered answer* is
acceptable — a question hidden by skip logic is simply not presented at all.

In the underlying survey schema, skip logic is stored as the **`relevant`**
field. In the designer, you configure it through **Skip Logic**.

---


## Where to configure it {#where-to-configure-it}


1. Open your survey in the **Survey Designer**.
2. Select the question in the canvas.
3. In the right-hand **Properties** panel, scroll to the **Advanced** section.
4. Click **Skip Logic**.

The **Skip Logic Builder** opens with two tabs:

- **Visual Builder** — add conditions ("when `age` is greater than or equal to
  18"), combine them with **AND** / **OR**, and nest groups of conditions.
- **Raw Expression** — type the expression directly in a client-friendly
  format (see below).

The generated XPath expression is shown as you build, and it is validated
against the server when you save. Questions with no conditions are always shown.

> **Scope rule:** A question inside a group can only reference questions in its
> **same group** plus **top-level** questions. A top-level question cannot
> reference a question inside a group. This keeps skip logic predictable.

---


## The two expression formats {#the-two-expression-formats}



### Raw expression (what you type) {#raw-expression-what-you-type}


The Raw Expression tab uses a compact, client-friendly format:

```text
age >= 18 & has_children = Yes
```

- `&` means **AND**
- `|` means **OR**
- Values with spaces do not need quotes
- Use parentheses for grouping: `facility_type=Primary Health Centre&(region=North|region=South)`


### Internal format (what is stored) {#internal-format-what-is-stored}


The builder converts what you type into the internal XPath format that is
stored with the question and evaluated at runtime:

```text
${age} >= 18 and ${has_children} = 'Yes'
```

You will see the internal format in the **Generated Expression** preview. If you
paste an existing XLSForm expression (the internal format), the builder parses
it back into the visual builder automatically.

---


## Simple equality {#simple-equality}


Show pregnancy questions only when the respondent's sex is female:

```text
${sex} = 'female'
```

In the raw tab, the same rule reads `sex = female`.


## Multiple conditions {#multiple-conditions}



### AND — all conditions must be true {#and--all-conditions-must-be-true}


Show questions only when the respondent is female **and** of age:

```text
${sex} = 'female' and ${age} >= 18
```


### OR — any condition may be true {#or--any-condition-may-be-true}


Show a section when either condition holds:

```text
${district} = 'Mumbai' or ${district} = 'Pune'
```


### Mixed AND / OR with parentheses {#mixed-and--or-with-parentheses}


```text
(${sex} = 'female' or ${sex} = 'trans_female') and ${age} >= 18
```


## Numeric conditions {#numeric-conditions}


Show adult employment questions when age is 18 or older:

```text
${age} >= 18
```

All comparison operators are available: `=`, `!=`, `<`, `<=`, `>`, `>=`.


## Select-one questions {#select-one-questions}


Show a "Specify other" question when **Other** is selected:

```text
${employer_type} = 'other'
```

For a select-one, a simple equality works because exactly one option is chosen.


## Select-multiple questions {#select-multiple-questions}


For multi-select questions, use `selected()` to test a single option:

```text
selected(${symptoms}, 'fever')
```

and `count-selected()` for the number of selected options:

```text
count-selected(${symptoms}) >= 2
```

> Note: `selected()` requires the option value (the variable name of the
> choice), not the displayed label.


## Nested skip logic {#nested-skip-logic}


Skip logic chains naturally. Question C can depend on Question B, which depends
on Question A:

```text
# Question A (no skip logic) — always shown
# Question B shown only when:
${consent} = 'yes'
# Question C shown only when BOTH:
${consent} = 'yes' and ${married} = 'yes'
```

When the answer that Question C depends on (e.g. consent) changes, MQUAD
re-evaluates C's visibility immediately. Hiding a question does **not** erase an
answer already entered for it — the value is retained (and re-shown if the
question becomes visible again). If you need a hidden value to be cleared, add
validation on the hidden question, or clear it by hand before submission.


## Date-based skip logic {#date-based-skip-logic}


Calculations and date functions are valid inside relevance expressions:

```text
date-diff('days', ${registration_date}, ${visit_date}) >= 30
```

Show the follow-up section when at least 30 days have passed since
registration. See [Date and Time Reference](/user-manual/date-time-reference.md) for the
exact rules of `date-diff`.


## Calculated-value-driven skip logic {#calculated-value-driven-skip-logic}


Skip logic can depend on a **calculated** value:

```text
${age} >= 18
```

where `age` is itself a calculated question:

```text
age(${dob}, ${interview_date})
```

MQUAD's dependency graph re-evaluates calculations first, then re-evaluates
relevance expressions that depend on them, so the section appears as soon as the
age computation updates. See [Auto-Populate and Calculations](/user-manual/calculation-expressions.md).

---


## Common mistakes {#common-mistakes}


- **Using the label instead of the variable name** — `sex = 'female'` uses the
  variable name, not the displayed question text.
- **Missing quotes on string values** — `district = Mumbai` may parse but won't
  match; use `district = Mumbai` in the raw tab (unquoted is accepted there) or
  `'Mumbai'` in the internal format.
- **Testing a multi-select with `=`** — a multi-select value can contain many
  options, so `symptoms = 'fever'` only matches when *fever is the only*
  selection. Use `selected(${symptoms}, 'fever')` instead.
- **Referencing a sibling-group question** — questions inside a group can only
  reference same-group and top-level questions. Move the referenced question to
  the top level if needed.
