Skip to content

IRenderable prompts, prompts with border styling and layout options - #2112

Open
MapelSiroup wants to merge 6 commits into
spectreconsole:mainfrom
MapelSiroup:irenderable-prompts-clean
Open

IRenderable prompts, prompts with border styling and layout options#2112
MapelSiroup wants to merge 6 commits into
spectreconsole:mainfrom
MapelSiroup:irenderable-prompts-clean

Conversation

@MapelSiroup

Copy link
Copy Markdown
Contributor

This Pull Request introduces IRenderable prompts, despite some prompts already having rendering features, TextPrompt now extends Live Renderable, and all Prompt types can now be inside panels, layouts, etc. All the while maintaining retro-compatibility with the old system.

New system works by setting up an initial prompt and then rendering it with await promptname.ShowAsRenderableAsync() when it is needed, you can also pass a custom IRenderable wrapper when rendering it.

Fixes #1281

  • I have read the Contribution Guidelines
  • I have checked that there isn't already another pull request that solves the above issue
  • All newly added code is adequately covered by tests
  • All existing tests are still running without errors

AI Agents used:

  • Claude Sonnet 4.6 : Reasoning + planning
  • Copilot Raptor mini 1x : code completion

Changes

The pullrequest does not change the old behavior of textprompt but introduces a way to render it using a render hook, LiveRenderable had to be updated in order to clear any overdraws or weird shapes with other renderables near it and so only 1 test expectation result had to be fixed due to an additional cursor input. All tests ran fine as of May 3rd.

Multiselection and SelectionPrompt had some existing features which made their implementation not too difficult.

The whole system works and is open to suggestions or code changes, but is, as described, a way to insert prompts as renderables. This is a cleaned up branch of the feature branch at MapelSiroup/spectre.console/irenderable-prompts

You can test functionality with the provided interactive tests located in my own fork: interactive tests examples

image image image

Usage Example:

public static async Task<IReadOnlyList<string>> AskMultiSelectionAsRenderableInLayout()
    {
        var prompt = new MultiSelectionPrompt<string>()
            .Title("Choose some colors")
            .AddChoices("Red", "Green", "Blue", "Yellow", "Cyan", "Magenta");

        var infoPanel = new Panel("[bold red]MultiSelection Prompt[/]\n\nUse space to select items/unselect, Enter to confirm.")
            .Header("Instructions", Justify.Center)
            .BorderColor(Color.Red)
            .BorderStyle(new Style().Background(Color.Black))
            .RoundedBorder();

        var layout = new Layout()
            .SplitRows(
                new Layout("Info")
                    .Update(infoPanel)
                    .Ratio(1),
                new Layout("Prompt")
                    .Update(new Panel("Placeholder"))
                    .Ratio(2));

        Func<IRenderable, IRenderable> wrapper = renderable => {
            layout["Prompt"].Update(new Panel(renderable)
                .Header("Color Selection Utility")
                .RoundedBorder()
                .BorderColor(Color.Blue));
            return layout;
        };

        return await prompt.ShowAsRenderableAsync(
            AnsiConsole.Console,
            wrapper,
            CancellationToken.None);
    }

This produces a prompt inside the layout, with the right styling as provided in the wrapper. then returns the list of strings when user confirms their selection.

Minimal example:

public static async Task<string> AskFruitSelectionAsRenderable()
    {
        var prompt = new SelectionPrompt<string>()
            .Title("Pick a fruit")
            .AddChoices("Apple", "Banana", "Cherry")
            .DefaultValue("Banana");

        return await prompt.ShowAsRenderableAsync(
            AnsiConsole.Console,
            renderable => new Panel(renderable)
                .Header("Select a fruit")
                .RoundedBorder()
                .BorderColor(Color.Green),
            CancellationToken.None);
    }

This produces a prompt with a minimal border using a panel, then returns the result when user confirms their selection.


Please upvote 👍 this pull request if you are interested in it.

@patriksvensson

Copy link
Copy Markdown
Contributor

Wow, this is impressive! Fair warning though: a PR this size is going to take me some time to review thoroughly. I'll get to it as soon as I can, but please bear with me.

Side note: There are some conflicts that need to be resolved.

@MapelSiroup

MapelSiroup commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

Yes, i am slightly aware of the conflict, not fully sure whats conflicting but i think its just a function signature out of order (Extension.Input -> readline -> swap cancelation token with InitialInput or something like that, unsure about the TextPrompt.cs but maybe some recent changes i forgot to port over), juggling between like 2-3 branches make me loose track of what's what sometimes.

I'll be around to fix it soon ish.

This is also very experiemental, i tried my best but im sure people will find it clunky or suggest changes so no need to rush the implementation of it in the main branch just yet, but yeah i would invite you to look at it whenever you have time :]

@github-actions github-actions Bot added the ⭐ top pull request Top pull request. label Jun 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⭐ top pull request Top pull request.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make prompts IRenderable

2 participants