---
title: "tuika 0.7.0"
description: "Release notes for tuika 0.7.0 (2026-07-31). Highlights: Responsive application primitives.; Rich HTML in Markdown.."
image: "https://tuika.dev/social-card.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://tuika.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# tuika 0.7.0

Released 2026-07-31. [crates.io](https://crates.io/crates/tuika/0.7.0) · [docs.rs](https://docs.rs/tuika/0.7.0/tuika/) · [GitHub release](https://github.com/everruns/tuika/releases/tag/v0.7.0)

Released alongside `tuika-html` 0.1.0, the new companion crate behind the
block-HTML boundary, plus `tuika-codeformatters` 0.4.0 and `tuika-mermaid` 0.2.0.
The existing companions adopt tuika 0.7's breaking view-measurement API and
update their tuika dependency requirement in the same release.

## Highlights

**Responsive application primitives.** Docked panels, target-relative overlays,
virtualized collections, semantic styles, and single-line input give hosts a
coherent framework for complex terminal applications without retained UI state.

![primitives demo](https://raw.githubusercontent.com/everruns/tuika/v0.7.0/docs/demos/primitives.gif)

**Rich HTML in Markdown.** Presentational inline HTML now shares Markdown's
styles, while the new parser-free `HtmlBlockRenderer` boundary lets `tuika-html`
render styled block HTML without adding a parser to tuika core.

![markdown HTML demo](https://raw.githubusercontent.com/everruns/tuika/v0.7.0/docs/demos/markdown_html.png)

## Added

- Wrapped flex lines with independent row/column gaps, grow and shrink weights,
  min/max constraints, `align_self`, cross-line `AlignContent`, and exact
  boundary-based cell rounding. `FlexItemStyle` separates child properties from
  `LayoutStyle`; `solve_layout` also reports resolved line geometry.
- `Flow` for intrinsic-width wrapping and a deliberately small equal-column
  row-major `Grid` component.
- Extensible `MeasureRequest` / `AvailableSpace` measurement, with known axes
  and definite/min-content/max-content modes. The default adapter preserves
  existing `View::measure` implementations.
- Runtime-neutral `RunnerCore`, configurable `TerminalSessionConfig`, and
  `testing::TestHarness` for state/signal/view application tests without a
  terminal or async runtime.
- `render_once` / `write_once` for ANSI-styled ordinary output, and `view!`
  `when(...)` / `for(... in ...)` composition.

- `Clock` and `SystemClock` provide one monotonic time boundary.
  `SelectionState::handle_with_clock` makes double-click gestures deterministic,
  and `Runner::with_clock` lets replayable synchronous hosts own tick time;
  existing `handle` and `Runner::new` behavior remains system-clock backed.
- `VirtualWindow` provides overflow-safe clamped and selection-centered ranges;
  `Scrollbar` renders the same window vertically or horizontally with semantic
  styling and local glyph/style overrides. Scroll, item scroll, viewport,
  select, and table now share those primitives. `SelectList::windowed` and
  `Table::windowed` accept only the visible records while preserving absolute
  selection and full-collection scrollbar geometry.
- `DockState`, `DockSpec`, and `DockLayout` provide a host-owned responsive
  lifecycle for one auxiliary panel: wide panels dock, narrow passive panels
  hide, and focused narrow panels resolve as overlay drawers without introducing
  a retained panel manager.
- Target-relative overlays: `TargetPlacement` selects above/below/left/right,
  cross-axis alignment, gap, and optional edge-aware flipping;
  `OverlaySpec::resolve_target` resolves it directly and
  `SceneOverlay::target` follows a `RectProbe` from the scene root in the same
  frame. Screen-anchored placement remains unchanged.
- `StyleRole` and `StyleResolver` form an open semantic styling boundary for hosts
  and companion crates. `RenderCtx::style` resolves built-in or namespaced
  application roles, resolver bundles partially overlay stylesheet defaults,
  and resolver revisions invalidate measurement caches. `paint_with_context`
  and `testing::render_with_context` install and test the complete policy.
- `ScopedElement<'view>`, the boxed frame-borrowed counterpart to owned
  `Element`, for heterogeneous component subtrees that read host state without
  cloning it.
- **Inline HTML in markdown.** The presentational inline tags render instead of
  being dropped: `<b>`/`<strong>`, `<i>`/`<em>`/`<var>`/`<cite>`/`<dfn>`,
  `<code>`/`<kbd>`/`<samp>`/`<tt>`, `<s>`/`<del>`/`<strike>`, `<u>`/`<ins>`,
  `<mark>`, `<a href>`, `<img src alt>`, `<br>`, and `<sub>`/`<sup>`. Each
  resolves the same `StyleSheet` role as the markdown construct it mirrors, so a
  host that restyles `strong` restyles `<b>` with it; `<a>` and `<img>` take the
  existing hyperlink and `ImageResolver` paths. No new dependency and no HTML
  parser: this is a fixed tag whitelist, so anything outside it — block-level
  HTML, `<script>`, unlisted attributes — is dropped as before, and never echoed
  as literal markup.
- **One structured markdown block boundary.** `MarkdownBlockRenderer` receives a
  non-exhaustive `MarkdownBlock` descriptor (`Fenced` or `Html`) and a shared
  `MarkdownBlockContext` containing width, theme, and the active stylesheet.
  `Markdown::block_renderer` and `MarkdownState::with_block_renderer` append to
  an ordered renderer chain, so Mermaid, HTML, and host-defined block parsers
  compose without adding another trait or field for every syntax.
- `tuika-html` bounds nesting on the source before parsing, so a fragment deep
  enough to overflow html5ever's recursive tree building is refused rather than
  crashing the host.
- **`markdown::Renderers`** builds the same ordered block-renderer chain for
  `markdown::to_lines_with` / `to_linked_lines_with`.
- `ProgressBar::label` draws a centered, clipped caption over determinate and
  indeterminate bars.
- `Scroll::wrap(true)` reflows owned styled lines at render width before
  applying the scroll window.
- `Table::selection_style` and `SelectList::selection_style` allow per-instance
  selection foreground, background, and modifiers.
- `SelectNavigation` policies for optional j/k, Ctrl+N/P, Tab/Shift+Tab, and
  numeric selection aliases; explicit mouse hit-testing on `SelectState`; and
  `MultiSelectState` for toggleable multiple-selection workflows.
- `KeyHints::from_keymap`, priority-aware whole-hint fitting, and `KeymapHelp`
  so one labeled keymap declaration drives dispatch, responsive footer hints,
  and a complete help view.
- `SingleLineInputState` for search/command fields, with newline normalization,
  Enter/Ctrl+J submission, and allocation-free borrowed text access.
- `tuika::ui` re-exports `Rect`, `Color`, `Style`, `Modifier`, `Line`, and `Span`
  for custom views without a direct `ratatui-core` dependency.
- `testing::render_with_sheet` renders consumer views under an explicit
  stylesheet in the same hermetic buffer harness as `testing::render`.

## Changed

- **Breaking:** `FencedBlockRenderer` and `HtmlBlockRenderer` are replaced by
  `MarkdownBlockRenderer`. Match on `MarkdownBlock`, read width/theme/sheet from
  `MarkdownBlockContext`, register every implementation through
  `block_renderer`, and build free-function chains with
  `Renderers::new().renderer(&first).renderer(&second)`. HTML fences now receive
  the host's active stylesheet instead of synthesizing theme defaults.
- **Breaking:** `LayoutStyle::gap` is split into `row_gap` and `column_gap`
  (the `.gap(...)` builder still sets both), and `Item::dimension` is replaced
  by `Item::style`. Use `Item::new` for the compatible compact path or
  `Item::styled(FlexItemStyle, ...)` for independent flex properties.

- **Breaking:** keymap character specs are now explicitly logical text. Write
  the character produced by the active layout (`A`, `?`, `ctrl+R`) rather than
  `shift+a` or `shift+/`; `Shift` remains valid for non-character chords such as
  `shift+enter`. Ambiguous `shift+character` specs now return `KeyParseError`
  (or panic through static `Layer::bind`) instead of silently discarding Shift.
- **Breaking:** `AsyncRunner` update closures now return `UpdateResult` instead
  of `ControlFlow<()>`, matching synchronous `Runner`; clean ticks and events no
  longer rebuild or repaint the view.

- **Breaking:** interactive component handlers now return one root/prelude
  `InputOutcome` (`Ignored`, `Consumed`, `Changed`, `Submitted`, or `Cancelled`).
  Read the submitted value back from its host-owned state. Replace
  `SelectOutcome`, `MultiSelectOutcome`, `FormOutcome`, `TabSelectOutcome`,
  `TextInputEvent`, and direct `EventFlow` matches with `InputOutcome`; call
  `.flow()` when only propagation matters. `SelectState`, `MultiSelectState`,
  and `ScrollState` now make `Default` identical to `new()`; use
  `SelectState::unselected()` for an initially cursorless list.
- **Breaking:** `StyleSheet` adds typed toast, diff, and key-hint fields. Toasts,
  diffs, `KeyHints`, and `KeymapHelp` now derive their defaults from those roles
  instead of renderer literals; explicit `Diff::style` colors still win for one
  instance. Exhaustive `StyleSheet` literals must add the new fields or use
  `..StyleSheet::from_theme(&theme)`. Construct `RenderCtx` through
  `RenderCtx::new` rather than a struct literal now that it carries the optional
  resolver.
- **Breaking:** `View::measure` now takes `&RenderCtx`, and every composition
  container forwards the frame's active theme, stylesheet, and focus state.
  Migrate `fn measure(&self, available: Size)` implementations to
  `fn measure(&self, available: Size, ctx: &RenderCtx)`; callers likewise pass
  the context used for rendering. `Flex::solve` now takes that context, and
  `ItemScroll::{measure_height, measure_views}` take it as their final argument.
- `Markdown` and the companion `tuika-html::Html` view now measure with the same
  theme and stylesheet they render with. `Boxed` implements stylesheet panel
  padding as real layout; an explicit `.padding(...)` wins over the stylesheet.
- `element`, `view!`, and composition containers now preserve borrowed child
  views at any depth. Existing owned trees continue to use `Element`; borrowed
  trees use the same builders and are bounded to their frame lifetime.
- `Flex` measures padded children against their actual inner box and reports
  fixed/percent child dimensions when the container itself is auto-sized, so
  nested measurement matches the rects assigned during rendering.
- `TextInputState` preserves grapheme clusters during cursor motion and
  deletion. Text input wrapping, rendering, and terminal cursor placement now
  share terminal-cell width, fixing CJK and multi-scalar emoji alignment while
  keeping public cursor and span coordinates as char indices.
- `FocusRegistry` immediately falls back to the first current registration when
  a focused id disappears from a dynamic frame, and commits that fallback at
  the next frame boundary instead of retaining or resurrecting a stale target.
- **Breaking:** synchronous `Runner::run` and `run_with_backend` now mirror the
  state/view/update shape of `AsyncRunner`: pass `&mut State`, render through
  `view(&State, frame)`, and handle `Signal` in `update(&mut State, Signal)`.
  Updates return `UpdateResult::{Clean, Dirty, Exit}` instead of
  `ControlFlow<()>`; ticks no longer repaint unless the update is dirty or a
  `RedrawHandle` fires.

- **Breaking**: `SelectState::selected()` now returns `Option<usize>`, and
  `SelectState::select` takes `Option<usize>`, so lists and tables can render
  without a selected row. Migrate `state.select(index)` to
  `state.select(Some(index))`; use `state.select(None)` or
  `SelectState::default()` for no selection. `SelectState::new()` still selects
  the first row.
- **Markdown output changes where the source contains inline HTML.** Text inside
  the whitelisted tags is now styled, `<br>` starts a new line, `<img>` becomes
  an image or an alt-text placeholder, and `<sub>`/`<sup>` digits become Unicode
  (`H<sub>2</sub>O` → `H₂O`). Markdown without HTML renders identically.
- Consecutive blank lines no longer appear in markdown output when a block
  renders nothing (a block-HTML run with no renderer attached), so a dropped
  block leaves no gap where it was.
- New gallery demo for inline HTML (`docs/demos/markdown_html.png`), referenced
  from the component gallery, the markdown guide, and `Markdown`'s rustdoc.
- `tuika-html` gains an example and a recording for the `Html` *component*
  (`cargo run -p tuika-html --example html_view`); the existing example covers
  the markdown boundary. `<sub>`/`<sup>` now transliterate there too, so one
  document cannot render `H₂O` through markdown and `H2O` through the crate,
  and `<dd>` hangs directly under its `<dt>` instead of a blank line below.
- `Table` now windows rows to its assigned render height by default.
  `Table::viewport(rows)` remains an optional upper bound.
- ratatui `Line` styles are composed underneath their `Span` styles in text,
  table cells, scrolling text, and box titles.
- `Boxed` titles start directly after the corner and truncate at the opposite
  corner, matching ratatui `Block` title placement.

Source: https://tuika.dev/releases/0.7.0/index.mdx
