Skip to content

Releases: charmbracelet/huh

v2.0.3

10 Mar 18:11
v2.0.3
3c0116c

Choose a tag to compare

This patch release fixes two UX issues where multiline options might get cutoff when navigating, and the other is related to ensuring the viewport width is updated after a resize.

Changelog

Fixed


The Charm logo

Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.

v2.0.2

10 Mar 17:34
v2.0.2
66bacd4

Choose a tag to compare

Paste Paste Paste

This patch release fixes an issue where sometimes, a paste event, might get triggered multiple times. Enjoy!

Changelog

Fixed

Docs


The Charm logo

Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.

v2.0.1

09 Mar 11:02
v2.0.1
c475304

Choose a tag to compare

This patch release includes upgrading the minimum Go version, upgrade our Bubble Tea and Lip Gloss libraries to use that latest and greatest patches. Enjoy!


The Charm logo

Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.

v2.0.0

09 Mar 10:52
v2.0.0
3efc5e5

Choose a tag to compare

Huh? v2?

We're thrilled to announce the second major release of Huh!

Note

We take API changes seriously, and we want to make the upgrade process as simple as possible.

❤️ Charm Land Import Path

We've updated our import paths to use vanity domains and use our domain to import Go packages.

// Before
import "github.com/charmbracelet/huh"

// After
import "charm.land/huh/v2"

🍵 Bubble Tea v2 & Lip Gloss v2

Huh v2 is built on the all-new Bubble Tea v2 and Lip Gloss v2, bringing all their improvements along for the ride:

  • The Cursed Renderer — optimized rendering built from the ground up on the ncurses algorithm
  • Better keyboard handling — progressive keyboard enhancements for modern terminals
  • Declarative views — no more fighting over terminal state
  • Built-in color downsampling — colors "just work" everywhere
  • And much more — see the Bubble Tea v2 release notes for the full picture

All these improvements come for free. Just upgrade and enjoy the performance and stability benefits.

🎨 Simpler Theming

Themes are now passed by value instead of pointer. This makes theme handling more straightforward and predictable.

// Before
form.WithTheme(huh.ThemeCharm())

// After
form.WithTheme(huh.ThemeCharm(false)) // false for light mode

All built-in themes now take a bool parameter to indicate whether the terminal has a dark background. Huh will automatically detect your terminal's background color, but you can also provide your own custom theme function:

type ThemeFunc func(isDark bool) *Styles

form.WithTheme(myCustomTheme)

🔍 View Hooks

Want to modify your form's view before it hits the screen? Now you can with WithViewHook:

form.WithViewHook(func(v tea.View) tea.View {
    // Modify the view properties
    v.AltScreen = true
    v.MouseMode = tea.MouseModeAllMotion
    return v
})

This is perfect for dynamically controlling terminal features, applying custom view transformations, or integrating Huh forms with larger Bubble Tea applications.

♿ Simplified Accessible Mode

The separate accessibility package is gone. Accessible mode is now built directly into Huh and controlled exclusively at the form level:

// Before - individual fields had their own accessible mode
input := huh.NewInput().
    Title("Name").
    WithAccessible(true)  // ❌ No longer exists on fields

select := huh.NewSelect[string]().
    Title("Pick one").
    Options(huh.NewOptions("A", "B", "C")...).
    WithAccessible(true)  // ❌ Removed from fields too

form := huh.NewForm(
    huh.NewGroup(input, select),
)

// After - only the form controls accessible mode
input := huh.NewInput().
    Title("Name")

select := huh.NewSelect[string]().
    Title("Pick one").
    Options(huh.NewOptions("A", "B", "C")...)

form := huh.NewForm(
    huh.NewGroup(input, select),
).WithAccessible(true)  // ✅ Set once at the form level

This makes accessible mode simpler and more consistent — one setting controls the entire form.

Tip

We recommend detecting accessible mode through environment variables or configuration options to let users control accessibility on their terms.

🗂️ Better Model Handling

The internal Model type is now exposed, making it easier to work with Huh forms in Bubble Tea applications. This improves type safety and makes composition patterns more natural.

func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    form, cmd := m.form.Update(msg)
    if f, ok := form.(huh.Model); ok {
        m.form = &f
    }
    return m, cmd
}

🧹 Cleaner Dependencies

Huh v2 benefits from the simplified dependency tree of Bubble Tea v2 and Lip Gloss v2. This means faster builds, smaller binaries, and fewer potential version conflicts.

🌈 More on Huh v2

Ready to migrate? Head over to the Upgrade Guide for the full migration checklist.


Changelog

New!

Fixed

Docs

Other stuff


Feedback

Have thoughts on Huh v2? We'd love to hear about it. Let us know on…


Part of Charm.

The Charm logo

Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة

v0.8.0

14 Oct 17:19
v0.8.0
a01a1e3

Choose a tag to compare

Fields aren’t just for farmers

Hi! This big feature in this release is that you can now create and maintain your own Field types as Field.RunAccessible is now public. Check out the Field interface and go crazy.

We also fixed a handful of bugs in the release. Special thanks to @pashpashpash for nudging us to cut a release.

Changelog

New!

  • feat: make Field.RunAccessible public, deprecate Field.WithAccessible by @caarlos0 in #667

Fixed

  • fix(select): do not show title if filter is set by @caarlos0 in #633
  • fix(select): make sure selected item is visible on viewport update by @caarlos0 in #632
  • fix(select,multiselect): properly handle defaults and prompts by @caarlos0 in #642
  • fix: Terminal.app rendering issues by @caarlos0 in #643
  • fix: minimize the risk of scrolling the view up on some terminals by @aymanbagabas in #649
  • fix: Add missing id initialization in field_select constructor by @forever-salty in #692

Other Stuff

New Contributors

Full Changelog: v0.7.0...v0.8.0

v0.7.0

16 Apr 19:33
151ba05

Choose a tag to compare

Less bugs, more feats

This is a quality-of-life release which fixes a handful of behavioral and rendering issues, and adds a few of useful features.

go get github.com/charmbracelet/huh@latest

Accessible mode: now more accessible

We made several updates to accessible mode, and it should now work better with
screen readers.

It will also now respect WithInput and WithOutput.

Focused? Hovered Filtered?

Useful when integrating with an existing Bubble Tea app, you can now get the
currently focused field, as well as the which option the cursor is pointing at, which we’re calling "hover":

f := huh.NewForm(
  huh.NewGroup(
    huh.NewSelect[string]().
      Options(huh.NewOptions(
        "Banana",
        "Apple",
        "Orange",
      )...).
      Title("Favorite fruit?"),
    huh.NewMultiSelect[string]().
      Options(huh.NewOptions(
        "Pudim",
        "Sagu",
        "Chocolate",
      )...).
      Title("Favorite dessert?"),
  ),
)
_ = f.Run()

field := f.GetFocusedField()
switch field := field.(type) {
case *huh.Select[string]:
  fmt.Println(field.Hovered())
case *huh.MultiSelect[string]:
  fmt.Println(field.Hovered())
}

You can also use GetFiltering to check if the user is currently filtering.

Spinning, but not out of control

Spinner was revamped and now properly handles context cancellations,
interrupts, and more. You can also use the new ActionWithError to set an action that might error.

Other improvements

  • FilePicker got a couple of improvements: you can now set the Cursor, and the UI has received a bit of extra polish.
  • Group now properly renders their Title and Description.
  • Text can now be configured to not allow opening the external editor.
  • Select and MultiSelect now properly handle multi-line options, as well as automatically wrap long options so they are properly rendered.
  • Title and Description of all components now properly wrap, fixing many rendering issues.
  • Both Column and Grid layouts received bug fixes and improvements.
  • Interrupt signals (SIGINT) are now properly handled.

Changelog

New Contributors


The Charm logo

Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse, or Discord.

v0.6.0

06 Sep 16:35
a9285a0

Choose a tag to compare

Just focus

This release features automatic window focus events support for the Input and Text components.

Note that if you're using Huh in a larger Bubble Tea program you’ll need WithReportFocus to enable focus events.

p := tea.NewProgram(model{}, tea.WithReportFocus())

Happy focusing!

Changelog

New!

Full Changelog: v0.5.3...v0.6.0

v0.5.3

23 Aug 13:41
5fd7081

Choose a tag to compare

Crushin’ bugs

This release fixes a buncha bugs in Huh and Gum alike. Gum users, stay tuned for an update later today.

What's Changed

Fixed

Other Stuff

New Contributors

Full Changelog: v0.5.2...v0.5.3

v0.5.2

24 Jul 18:14
41be8ec

Choose a tag to compare

Lil’ fixes ’n’ improvements

Hi! This is a maintenance release to fix issues with dynamic forms as well as address issues with Gum upstream.

Changelog

New

Fixed

  • improve distinction in field select by @csandeep in #304
  • fix invalid order of event handling in input/text fields by @Sculas in #284

New Contributors

Full Changelog: v0.5.1...v0.5.2


The Charm logo

Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse, or Discord.

v0.5.0

09 Jul 22:11
v0.5.0
4289f94

Choose a tag to compare

This big news in this release is that forms in Huh can now be dynamic. Read on for more:

Dynamic Forms 🪄

Country / State form with dynamic inputs running.

huh? forms can now react to changes in other parts of the form. Replace properties such as Options, Title, Description with their dynamic counterparts: OptionsFunc, TitleFunc, and DescriptionFunc to recompute properties values on changes when watched variables change.

Let’s build a simple state / province picker.

var country string
var state string

The country select will be static, we’ll use this value to recompute the
options and title for the next input.

huh.NewSelect[string]().
    Options(huh.NewOptions("United States", "Canada", "Mexico")...).
    Value(&country).
    Title("Country").

Define your Select with TitleFunc and OptionsFunc and bind them to the
&country value from the previous field. Whenever the user chooses a different
country, the TitleFunc and OptionsFunc will be recomputed.

Important

We have to pass &country as the binding to recompute the function only when
country changes, otherwise we will hit the API too often.

huh.NewSelect[string]().
    Value(&state).
    Height(8).
    TitleFunc(func() string {
        switch country {
        case "United States":
            return "State"
        case "Canada":
            return "Province"
        default:
            return "Territory"
        }
    }, &country).
    OptionsFunc(func() []huh.Option[string] {
        opts := fetchStatesForCountry(country)
        return huh.NewOptions(opts...)
    }, &country),

Lastly, run the form with these inputs.

err := form.Run()
if err != nil {
    log.Fatal(err)
}

Changelog

New!

Fixed

New Contributors

Full Changelog: v0.4.2...v0.5.0


The Charm logo

Thoughts? Questions? We love hearing from you. Feel free to reach out on Twitter, The Fediverse, or Discord.