React to button click not keystrokes

To drive the search you can gate the DataSource with a triggerSearch variable that's initially false. The Button click transfers the TextBox value to the submittedSearch variable and also sets triggerSearch true. Now the query runs and results display.

<App var.submittedSearch="" var.triggerSearch="{false}">
  <DataSource
      id="searchResults"
      url="/api/search"
      body="{JSON.stringify({query: submittedSearch})}"
      method="POST"
      when="{triggerSearch}"
      onDidLoad="triggerSearch = false"
    />
  <HStack>
    <TextBox
      id="searchInput"
      width="300px"
      placeholder="Search text..."
    />
    <Button
      label="Search"
      onClick="submittedSearch = searchInput.value; triggerSearch = true"
    />
  </HStack>
  <Fragment when="{searchResults.loaded}">
    <Text>Search results for: {submittedSearch}</Text>
    <Text>Found {searchResults.value.results.length}</Text>
    <List data="{searchResults.value.results}"/>
  </Fragment>
</App>
Try searching for 'xmlui' or 'best'
<App var.submittedSearch="" var.triggerSearch="{false}">
  <DataSource
      id="searchResults"
      url="/api/search"
      body="{JSON.stringify({query: submittedSearch})}"
      method="POST"
      when="{triggerSearch}"
      onDidLoad="triggerSearch = false"
    />
  <HStack>
    <TextBox
      id="searchInput"
      width="300px"
      placeholder="Search text..."
    />
    <Button
      label="Search"
      onClick="submittedSearch = searchInput.value; triggerSearch = true"
    />
  </HStack>
  <Fragment when="{searchResults.loaded}">
    <Text>Search results for: {submittedSearch}</Text>
    <Text>Found {searchResults.value.results.length}</Text>
    <List data="{searchResults.value.results}"/>
  </Fragment>
</App>

Alternatively, you can gate the DataSource on an initially-empty submittedSearch. Update a typedSearch variable when the TextBox changes. On the Button click, update typedSearch to submittedSearch. Now the query runs and results display.

<App var.typedSearch="" var.submittedSearch="">
  <DataSource
    id="searchResults"
    url="/api/search"
    body="{JSON.stringify({ query: submittedSearch })}"
    method="POST"
    when="{submittedSearch !== ''}"
  />
  <HStack>
    <TextBox
      placeholder="Search text..."
      width="300px"
      onDidChange="(value) => typedSearch = value"
    />
    <Button
      label="Search"
      onClick="submittedSearch = typedSearch"
    />
  </HStack>
  <Fragment when="{searchResults.loaded}">
    <Text>Search results for: {submittedSearch}</Text>
    <Text>Found {searchResults.value.results.length}</Text>
    <List data="{searchResults.value.results}"/>
  </Fragment>
</App>
Try searching for 'xmlui' or 'best'
<App var.typedSearch="" var.submittedSearch="">
  <DataSource
    id="searchResults"
    url="/api/search"
    body="{JSON.stringify({ query: submittedSearch })}"
    method="POST"
    when="{submittedSearch !== ''}"
  />
  <HStack>
    <TextBox
      placeholder="Search text..."
      width="300px"
      onDidChange="(value) => typedSearch = value"
    />
    <Button
      label="Search"
      onClick="submittedSearch = typedSearch"
    />
  </HStack>
  <Fragment when="{searchResults.loaded}">
    <Text>Search results for: {submittedSearch}</Text>
    <Text>Found {searchResults.value.results.length}</Text>
    <List data="{searchResults.value.results}"/>
  </Fragment>
</App>