Professional Input UI in v6

Fact checked by
Mike Christensen, CFOA
March 11, 2026
How to design professional Pine Script input settings using v6 active inputs, enum dropdowns, groups, and conditional visibility patterns.

Bottom Line

  • Combine enum inputs for dropdown selection with the active parameter for conditional visibility of related settings
  • Use input groups and inline parameters to organize settings into logical sections with clean layout
  • Create mode-based UIs where selecting one strategy mode reveals only its relevant parameters
  • Design tooltip strings that explain each input's purpose using the longer 40960-character string limit

The Settings panel is where most users form their first impression of your Pine Script indicator. A script with thirty unorganized inputs scattered across a single flat list feels intimidating and amateurish. A script with the same thirty inputs organized into logical groups, with irrelevant settings automatically grayed out and helpful tooltips on every field, feels professional and trustworthy. The difference is entirely in how you design the input UI.

Pine Script v6 introduced several features that make professional input design possible1. Enum dropdowns replace fragile string comparisons. The active parameter creates conditional visibility where related settings dim when their parent toggle is off. Groups and inline parameters organize inputs into clean sections. This guide walks through each of these features and finishes with a complete example of a professional strategy settings panel.

Why Input Design Matters

Script adoption on TradingView depends heavily on usability. Two scripts with identical logic will see very different adoption rates if one has clean, organized settings and the other has a wall of unstructured inputs. Good input design accomplishes three things.

  • It reduces cognitive load by showing users only the settings that matter for their current configuration
  • It prevents errors by constraining choices to valid options through dropdowns instead of free-text fields
  • It communicates professionalism and builds trust that the underlying calculations are equally well-crafted

The v6 features covered in this guide require no advanced programming knowledge. They are all parameters on the standard input functions you already use.

Enum Dropdowns

In Pine Script v5, dropdown menus required input.string() with an options list of raw strings2. Your code then compared the selected string to string literals, which was error-prone and cluttered.

The v5 String Approach

// v5 approach - fragile string comparisons
string maTypeInput = input.string("SMA", "MA Type", options = ["SMA", "EMA", "WMA", "VWMA"])
float maResult = maTypeInput == "SMA" ? ta.sma(close, 20) :
                 maTypeInput == "EMA" ? ta.ema(close, 20) :
                 maTypeInput == "WMA" ? ta.wma(close, 20) :
                 ta.vwma(close, 20)

The problem is that every comparison uses a raw string literal. If you misspell "SMA" as "sma" in one comparison, the logic breaks silently. There is no compiler check to catch the error.

The v6 Enum Approach

Pine Script v6 enums define a named set of valid values1. The input.enum() function creates a dropdown that maps directly to enum members3. All comparisons use named constants, so typos produce compiler errors instead of silent bugs.

//@version=6
indicator("Enum dropdown demo", overlay = true)

//@enum         Moving average type options for the indicator.
//@field sma    Simple Moving Average
//@field ema    Exponential Moving Average
//@field wma    Weighted Moving Average
//@field vwma   Volume Weighted Moving Average
enum MAType
    sma  = "Simple (SMA)"
    ema  = "Exponential (EMA)"
    wma  = "Weighted (WMA)"
    vwma = "Volume Weighted (VWMA)"

MAType maTypeInput = input.enum(MAType.sma, "MA Type")
int    maLenInput  = input.int(20, "MA Length", minval = 1)

float maResult = switch maTypeInput
    MAType.sma  => ta.sma(close, maLenInput)
    MAType.ema  => ta.ema(close, maLenInput)
    MAType.wma  => ta.wma(close, maLenInput)
    MAType.vwma => ta.vwma(close, maLenInput)

plot(maResult, "MA", color.blue, 2)

The field titles in the enum declaration are the strings displayed in the dropdown. The field names (sma, ema, wma, vwma) are the named constants used in your code logic. If you write MAType.smaa by mistake, the compiler catches it immediately. The switch statement covers every possible value with no ambiguity.

Restricting Options

You can limit which enum members appear in the dropdown by passing an options argument to input.enum()3. This is useful when the same enum is shared across multiple scripts but a specific script only supports a subset of the options.

MAType maTypeInput = input.enum(MAType.sma, "MA Type", options = [MAType.sma, MAType.ema])

Now only the Simple and Exponential options appear in the dropdown, even though the enum defines four members.

Grouping Related Inputs

The group parameter on any input function places that input into a named section in the Settings panel3. The section heading appears as collapsible text, and all inputs with the same group string appear together regardless of their order in the source code.

//@version=6
indicator("Grouped inputs demo", overlay = true)

// --- Moving Average Group ---
string GRP_MA = "Moving Average"
MAType maTypeInput = input.enum(MAType.sma, "Type", group = GRP_MA)
int    maLenInput  = input.int(20, "Length", minval = 1, group = GRP_MA)
color  maClrInput  = input.color(color.blue, "Color", group = GRP_MA)

// --- Bollinger Bands Group ---
string GRP_BB = "Bollinger Bands"
bool   showBBInput   = input.bool(true, "Show Bands", group = GRP_BB)
float  bbMultInput   = input.float(2.0, "Multiplier", minval = 0.5, step = 0.5, group = GRP_BB)
color  bbClrInput    = input.color(color.gray, "Band Color", group = GRP_BB)

Storing the group string in a constant variable (GRP_MA, GRP_BB) ensures consistency. If you need to rename a section later, you change it in one place. The group string is case-sensitive, so "Moving Average" and "moving average" would create two separate sections.

Inline Inputs for Compact Layouts

The inline parameter places multiple inputs on the same line in the Settings panel3. This is ideal for pairs of related settings like a value and its color, or a length and its source.

int    maLenInput = input.int(20, "MA", inline = "ma_line", group = GRP_MA)
color  maClrInput = input.color(color.blue, "", inline = "ma_line", group = GRP_MA)

Both inputs share the inline string "ma_line", so they appear on the same row. The color input uses an empty title because the label from the length input already identifies the line. The particular string used for inline is arbitrary and does not appear in the UI. It only needs to match across inputs that belong on the same line.

When using inline, input fields sit immediately to the right of their labels rather than being left-aligned in a column. If you have multiple inline rows with labels of different lengths, the fields will not align vertically. You can fix this by padding shorter labels with Unicode EN spaces (U+2002) to match the width of the longest label.

Conditional Visibility With Active

The active parameter is the single most impactful feature for professional input design1. When active is false, the input appears grayed out and users cannot change its value. When active is true (the default), the input works normally3. Because active accepts an "input bool" argument, you can tie it directly to the value of another input.

Basic Toggle Pattern

//@version=6
indicator("Active inputs demo", overlay = true)

// --- Smoothing toggle controls child inputs ---
bool  showSmoothInput  = input.bool(false, "Enable Smoothing", group = "Smoothing")
int   smoothLenInput   = input.int(10, "Smoothing Length", minval = 1, group = "Smoothing", active = showSmoothInput)
color smoothClrInput   = input.color(color.orange, "Smoothing Color", group = "Smoothing", active = showSmoothInput)

float rawMA = ta.sma(close, 20)
float smoothedMA = showSmoothInput ? ta.sma(rawMA, smoothLenInput) : rawMA

plot(smoothedMA, "MA", showSmoothInput ? smoothClrInput : color.blue, 2)

When "Enable Smoothing" is unchecked, the length and color inputs below it are grayed out. Users can see they exist but cannot interact with them until they check the parent toggle. This immediately communicates which settings are relevant to the current configuration.

Enum-Driven Conditional Visibility

The most powerful pattern combines enum dropdowns with active to create mode-based settings. Selecting a mode from the dropdown reveals only the inputs relevant to that mode.

//@version=6
indicator("Mode-based inputs demo", overlay = true)

//@enum         Strategy modes with descriptive titles.
//@field trend  Trend-following mode using moving average crossovers.
//@field mean   Mean reversion mode using Bollinger Band extremes.
//@field breakout Breakout mode using Donchian channel violations.
enum StrategyMode
    trend    = "Trend Following"
    mean     = "Mean Reversion"
    breakout = "Breakout"

StrategyMode modeInput = input.enum(StrategyMode.trend, "Strategy Mode", group = "Mode")

// --- Trend Following Settings ---
string GRP_TREND = "Trend Following Settings"
int fastMAInput = input.int(10, "Fast MA Length", minval = 1, group = GRP_TREND, active = modeInput == StrategyMode.trend)
int slowMAInput = input.int(50, "Slow MA Length", minval = 1, group = GRP_TREND, active = modeInput == StrategyMode.trend)

// --- Mean Reversion Settings ---
string GRP_MEAN = "Mean Reversion Settings"
int    bbLenInput  = input.int(20, "BB Length", minval = 1, group = GRP_MEAN, active = modeInput == StrategyMode.mean)
float  bbMultInput = input.float(2.0, "BB Multiplier", minval = 0.5, step = 0.5, group = GRP_MEAN, active = modeInput == StrategyMode.mean)

// --- Breakout Settings ---
string GRP_BRK = "Breakout Settings"
int    donchianLenInput = input.int(20, "Channel Length", minval = 1, group = GRP_BRK, active = modeInput == StrategyMode.breakout)
bool   trailStopInput   = input.bool(true, "Use Trailing Stop", group = GRP_BRK, active = modeInput == StrategyMode.breakout)

When the user selects "Trend Following" from the mode dropdown, only the fast and slow MA inputs are active. The Bollinger Band and Donchian Channel inputs are all grayed out. Switch to "Mean Reversion" and the BB settings activate while everything else dims. This pattern scales to any number of modes and keeps the settings panel clean regardless of how many total inputs the script contains.

Tooltips and Descriptions

The tooltip parameter adds a question mark icon next to the input field. Hovering over it displays the tooltip text. This is where you explain what the input does, what valid ranges are, and any important caveats.

int maLenInput = input.int(20, "MA Length", minval = 1,
     tooltip = "Number of bars for the moving average calculation.\nHigher values produce smoother results but lag more.\nRecommended range: 10-200.")

Tooltips support newline characters with \n for formatting. The tooltip text can be up to 40,960 characters long, which is the same limit as input.string() and input.text_area() text fields3. Use this space to document complex parameters thoroughly. A well-written tooltip eliminates the need for a separate documentation page.

When multiple inputs share the same inline row, the tooltip icon appears to the right of the last input on that line. Only the tooltip from the last input in the row is displayed4. Plan your inline groupings accordingly.

Complete Example: Professional Settings

This example combines every pattern discussed above into a single indicator with a professional-grade settings panel. It implements a multi-mode moving average indicator with optional Bollinger Bands, signal markers, and a dashboard table.

//@version=6
indicator("Professional Settings Demo", overlay = true)

// =============================================
// ENUMS
// =============================================
//@enum Moving average calculation methods.
enum MAMethod
    sma  = "Simple (SMA)"
    ema  = "Exponential (EMA)"
    wma  = "Weighted (WMA)"
    vwma = "Volume Weighted (VWMA)"

//@enum Signal display modes.
enum SignalDisplay
    arrows = "Arrow Markers"
    colors = "Bar Colors"
    off    = "Off"

// =============================================
// INPUTS - Main Settings
// =============================================
string GRP_MAIN = "Main Settings"
MAMethod   maMethodInput = input.enum(MAMethod.sma, "MA Method", group = GRP_MAIN, tooltip = "Select the moving average calculation method")
int        maLenInput    = input.int(20, "Length", minval = 1, maxval = 500, group = GRP_MAIN, inline = "ma")
color      maClrInput    = input.color(color.blue, "", group = GRP_MAIN, inline = "ma")
float srcInput            = input.source(close, "Source", group = GRP_MAIN)

// =============================================
// INPUTS - Bollinger Bands (conditional)
// =============================================
string GRP_BB = "Bollinger Bands"
bool  showBBInput  = input.bool(false, "Enable Bands", group = GRP_BB)
float bbMultInput  = input.float(2.0, "Multiplier", minval = 0.5, step = 0.5, group = GRP_BB, active = showBBInput, inline = "bb")
color bbClrInput   = input.color(color.gray, "", group = GRP_BB, active = showBBInput, inline = "bb")

// =============================================
// INPUTS - Signals (conditional)
// =============================================
string GRP_SIG = "Signals"
SignalDisplay sigModeInput = input.enum(SignalDisplay.off, "Display Mode", group = GRP_SIG)
bool sigActive = sigModeInput != SignalDisplay.off
color sigBullInput = input.color(color.teal, "Bull", group = GRP_SIG, active = sigActive, inline = "sigclr")
color sigBearInput = input.color(color.red, "Bear", group = GRP_SIG, active = sigActive, inline = "sigclr")

// =============================================
// CALCULATIONS
// =============================================
float ma = switch maMethodInput
    MAMethod.sma  => ta.sma(srcInput, maLenInput)
    MAMethod.ema  => ta.ema(srcInput, maLenInput)
    MAMethod.wma  => ta.wma(srcInput, maLenInput)
    MAMethod.vwma => ta.vwma(srcInput, maLenInput)

float bbBasis = ta.stdev(srcInput, maLenInput) * bbMultInput
float bbUpper = ma + bbBasis
float bbLower = ma - bbBasis

bool bullSignal = ta.crossover(close, ma)
bool bearSignal = ta.crossunder(close, ma)

// =============================================
// PLOTTING
// =============================================
plot(ma, "Moving Average", maClrInput, 2)
plot(showBBInput ? bbUpper : na, "BB Upper", bbClrInput)
plot(showBBInput ? bbLower : na, "BB Lower", bbClrInput)

// Arrow signals
plotshape(sigModeInput == SignalDisplay.arrows and bullSignal ? low : na, "Bull Signal", shape.triangleup, location.belowbar, sigBullInput, size = size.small)
plotshape(sigModeInput == SignalDisplay.arrows and bearSignal ? high : na, "Bear Signal", shape.triangledown, location.abovebar, sigBearInput, size = size.small)

// Bar color signals
barcolor(sigModeInput == SignalDisplay.colors ? (close > ma ? sigBullInput : sigBearInput) : na)

What Makes This Professional

The settings panel for this indicator has a clear visual hierarchy. The main settings group appears first with the most important choices. The Bollinger Bands section is entirely optional and only activates when the user checks the toggle. The Signals section uses an enum dropdown with three modes, and the color inputs only activate when a signal mode is selected.

  • Enum dropdowns ensure type-safe comparisons with no risk of string typos1
  • Groups separate settings into logical categories with clear headings3
  • Inline parameters pair values with their colors on the same row3
  • Active parameter grays out irrelevant settings based on the current configuration3
  • Tooltips explain each input's purpose and valid ranges4

Before and After Comparison

To illustrate the difference these patterns make, consider the same indicator written without any of the v6 input features.

Unstructured v5 Style

// v5 style - flat, unorganized, all always editable
string maType = input.string("SMA", "MA Type", options = ["SMA", "EMA", "WMA", "VWMA"])
int maLen = input.int(20, "MA Length")
color maColor = input.color(color.blue, "MA Color")
bool showBB = input.bool(false, "Show BB")
float bbMult = input.float(2.0, "BB Mult")
color bbColor = input.color(color.gray, "BB Color")
string sigMode = input.string("Off", "Signal Mode", options = ["Arrows", "Bar Colors", "Off"])
color bullColor = input.color(color.green, "Bull Color")
color bearColor = input.color(color.red, "Bear Color")

All nine inputs appear in a single flat list. The BB multiplier and color are always editable even when bands are hidden. The signal colors are always editable even when signals are turned off. There is no visual grouping and no indication of which settings relate to which feature.

Structured v6 Style

The v6 version shown in the complete example above has the same nine inputs organized into three collapsible groups. Five of the nine inputs are conditionally active, only becoming editable when their parent feature is enabled3. Dropdown menus use type-safe enums instead of raw strings2. The result is a settings panel that feels deliberately designed rather than thrown together.

Design Guidelines

When designing input panels for your own scripts, follow these principles for the best user experience.

  • Place the most important settings in the first group so users see them immediately
  • Use a boolean toggle as the gate for each optional feature and connect it to child inputs via active
  • Pair every numeric input with its color input on the same inline row
  • Write tooltips for any input whose purpose is not immediately obvious from its label
  • Use enum types for any selection with three or more options instead of string dropdowns
  • Keep group names short and descriptive using no more than three or four words
  • Align inline labels using Unicode EN spaces (U+2002) when multiple inline rows have different label lengths

The combination of these patterns produces settings panels that rival commercial TradingView indicators. Your users will spend less time configuring and more time using your scripts, which translates directly into higher adoption, better reviews, and more followers on TradingView.

References

1 Pine Script Release Notes
2 Pine Script v5 to v6 Migration Guide
3 Pine Script v6 Language Reference
4 Pine Script User Manual

Ready to automate your trading? Try a free 7-day account:
Try it for free ->