A comprehensive Flutter package for Japanese vertical text (縦書き) layout with advanced typography features.
- Basic Vertical Text Layout: Top-to-bottom, right-to-left Japanese text rendering
- Ruby (Furigana): Phonetic guide text beside characters
- Kenten (圏点): Various styles of emphasis marks (sesame, circles, triangles, etc.)
- Tatechuyoko (縦中横): Horizontal text within vertical layout (for numbers, dates)
- Warichu (割注): Two-line inline annotations
- Text Decoration (傍線): Sideline decorations (single, double, wavy, dotted)
- Text Alignment (地付き/天付き): Line-level vertical alignment
TextAlignment.start(天付き): Align to topTextAlignment.center: Center alignment (default)TextAlignment.end(地付き): Align to bottom
- Text Selection: Interactive text selection with copy support
- Advanced Kinsoku Shori (禁則処理): Proper line breaking rules for Japanese typography
- Kerning: Advanced character spacing adjustments for professional typography
- Yakumono Adjustment (約物調整): Fine-tuned punctuation positioning
- Burasage-gumi (ぶら下げ組): Hanging punctuation at line ends
- Half-width punctuation (半角処理): Treats certain punctuation as 0.5 character width
- Gyoto indent (行頭括弧の字下げ): Indented opening brackets at line start
- Consecutive punctuation spacing: Tightened spacing between adjacent punctuation
- RichText Support: Multiple text styles, colors, and sizes in a single vertical text
- Figure Layout: Image placement with captions and text wrapping support
This package is part of the Japanese text layout suite:
| Package | Description |
|---|---|
| kinsoku | Core text processing (line breaking, character classification) |
| tategaki | Vertical text layout (this package) |
| yokogaki | Horizontal text layout (横書き) |
3ステップで縦書きテキストを表示:
// 1. Import
import 'package:tategaki/tategaki.dart';
// 2. Widget内で使用
VerticalText(
'こんにちは、世界!',
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 24),
),
)ルビ付きの例:
VerticalText(
'日本語',
ruby: const [RubyText(startIndex: 0, length: 3, ruby: 'にほんご')],
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 32),
rubyStyle: TextStyle(fontSize: 14),
),
)| Platform | Status | Notes |
|---|---|---|
| Android | ✅ Supported | All features |
| iOS | ✅ Supported | All features |
| Web | ✅ Supported | All features |
| Windows | ✅ Supported | All features |
| macOS | ✅ Supported | All features |
| Linux | ✅ Supported | All features |
Requirements:
- Flutter: ≥1.17.0
- Dart SDK: ≥3.10.3
Add this to your package's pubspec.yaml file:
dependencies:
tategaki: ^0.6.5Then run:
flutter pub getThe simplest way to display vertical Japanese text:
import 'package:flutter/material.dart';
import 'package:tategaki/tategaki.dart';
VerticalText(
'これは縦書きテキストの例です。日本語の伝統的な文書では、このように縦書きで文字を配置します。',
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 24, color: Colors.black87),
characterSpacing: 4,
lineSpacing: 24,
),
maxHeight: 400, // Wrap to next line after 400px height
)Add phonetic guides to your vertical text:
VerticalText(
'日本語',
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 32, color: Colors.black87),
rubyStyle: TextStyle(fontSize: 14, color: Colors.blue),
),
ruby: const [
RubyText(startIndex: 0, length: 3, ruby: 'にほんご'),
],
)Add emphasis marks to important text:
VerticalText(
'重要な内容です',
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 28, color: Colors.black87),
characterSpacing: 6,
),
kenten: const [
Kenten(startIndex: 0, length: 2, style: KentenStyle.filledCircle),
],
)Available kenten styles:
KentenStyle.sesame- ゴマ点 (•)KentenStyle.filledCircle- 黒丸 (●)KentenStyle.circle- 白丸 (○)KentenStyle.filledTriangle- 黒三角 (▲)KentenStyle.triangle- 白三角 (△)KentenStyle.doubleCircle- 二重丸 (◎)
Control line-level vertical alignment:
VerticalText(
'地付きの例です。',
style: VerticalTextStyle(
baseStyle: TextStyle(fontSize: 24),
alignment: TextAlignment.end, // 地付き - align to bottom
),
maxHeight: 400,
)Automatically convert 2-digit numbers to horizontal layout within vertical text:
VerticalText(
'令和06年12月25日',
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 28, color: Colors.black87),
characterSpacing: 4,
),
autoTatechuyoko: true, // Automatically detects 06, 12, 25
)Enable text selection with copy support:
SelectableVerticalText(
'これは選択可能な縦書きテキストです。',
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 24),
),
maxHeight: 400,
)Use SelectionAreaVerticalText inside SelectionArea to enable unified text selection across multiple widgets:
SelectionArea(
child: Row(
children: [
SelectableText('横書きテキスト'),
SelectionAreaVerticalText(
text: '縦書きテキスト',
style: VerticalTextStyle(
baseStyle: TextStyle(fontSize: 24),
),
rubyList: [
RubyText(startIndex: 0, length: 2, ruby: 'たて'),
],
maxHeight: 300,
),
],
),
)This allows seamless text selection that spans across vertical and horizontal text widgets.
For reading apps where drag gestures should scroll content rather than select text, use LongPressSelectableVerticalText. Selection only starts after a long press (similar to Android Chrome):
LongPressSelectableVerticalText(
text: 'これは長押しで選択可能な縦書きテキストです。',
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 24),
),
maxHeight: 400,
// Optional: customize long press duration (default: 500ms)
longPressDuration: Duration(milliseconds: 500),
)Features:
- Long press to start selection (word-by-word using TinySegmenter)
- Drag to extend selection
- Copy menu with haptic feedback
- Tap to dismiss selection
Enable professional Japanese typography features:
VerticalText(
'「これは、約物調整の例です。」と彼は言った。',
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 24, color: Colors.black87),
characterSpacing: 4,
enableKerning: true, // Adjust spacing between characters
enableHalfWidthYakumono: true, // Treat 。、as half-width
enableBurasageGumi: true, // Allow punctuation to hang
enableGyotoIndent: true, // Indent opening brackets
adjustYakumono: true, // Fine-tune punctuation positions
),
maxHeight: 400,
)Proper Japanese line breaking that respects forbidden positions:
VerticalText(
'これは禁則処理のデモです。行頭や行末に来てはいけない文字(句読点や括弧など)が適切に処理されます。',
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 22, color: Colors.black87),
characterSpacing: 3,
lineSpacing: 20,
),
maxHeight: 300, // Kinsoku rules apply at line breaks
)The package automatically:
- Prevents punctuation (。、!?) from appearing at line start
- Prevents opening brackets ((「【) from appearing at line end
- Keeps inseparable character pairs (…… ) together
Create vertical text with multiple fonts, colors, and sizes:
VerticalRichText(
textSpan: VerticalTextSpan(
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 24, color: Colors.black87),
characterSpacing: 4,
),
children: [
const VerticalTextSpan(text: 'これは'),
VerticalTextSpan(
text: '強調された',
style: const VerticalTextStyle(
baseStyle: TextStyle(
fontSize: 24,
color: Colors.red,
fontWeight: FontWeight.bold,
),
characterSpacing: 4,
),
),
const VerticalTextSpan(text: 'テキスト'),
VerticalTextSpan(
text: 'です',
style: const VerticalTextStyle(
baseStyle: TextStyle(
fontSize: 28,
color: Colors.blue,
),
characterSpacing: 4,
),
),
],
),
maxHeight: 400,
)Combine all features for professional Japanese text layout:
VerticalText(
'昭和(1926年)12月25日。「美しい日本語の組版」を実現する為に、様々な工夫が凝らされている。',
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 20, color: Colors.black87),
characterSpacing: 3,
lineSpacing: 18,
enableKerning: true,
enableHalfWidthYakumono: true,
enableBurasageGumi: true,
enableGyotoIndent: true,
adjustYakumono: true,
),
autoTatechuyoko: true,
maxHeight: 350,
)| Property | Type | Default | Description |
|---|---|---|---|
baseStyle |
TextStyle |
- | Base text style (font, size, color, etc.) |
characterSpacing |
double |
0 |
Vertical spacing between characters |
lineSpacing |
double |
0 |
Horizontal spacing between lines |
alignment |
TextAlignment |
center |
Line-level alignment (start/center/end) |
rotateLatinCharacters |
bool |
false |
Rotate Latin characters 90° |
adjustYakumono |
bool |
true |
Enable yakumono position adjustments |
enableKerning |
bool |
false |
Enable advanced kerning |
enableHalfWidthYakumono |
bool |
false |
Treat certain punctuation as half-width |
enableBurasageGumi |
bool |
false |
Allow hanging punctuation at line ends |
enableGyotoIndent |
bool |
false |
Indent opening brackets at line start |
rubyStyle |
TextStyle? |
null |
Style for ruby (furigana) text |
Manually specify tatechuyoko ranges:
VerticalText(
'AB月CD日',
tatechuyoko: const [
Tatechuyoko(startIndex: 0, length: 2), // AB
Tatechuyoko(startIndex: 3, length: 2), // CD
],
)Place images within vertical text with captions:
VerticalText(
'本文テキスト',
figures: [
Figure(
child: Image.asset('image.png'),
position: 10,
alignment: FigureAlignment.center,
caption: '図1:説明文',
),
],
)Check out the /example directory for a comprehensive demo app showcasing all features.
To run the example:
cd example
flutter run- CustomPainter-based: Uses Flutter's CustomPainter for precise character positioning and rotation
- Character-level layout: Each character is individually positioned and rotated according to Japanese typography rules
- Advanced line breaking: Implements proper kinsoku shori (禁則処理) with look-ahead and backtracking
- Modular design: Separate utilities for character classification, rotation rules, kerning, and punctuation adjustment
The package implements proper Japanese typography rules following the W3C Japanese Text Layout Requirements:
- Character rotation for brackets, quotes, and dashes
- Small kana (っゃゅょ) size and position adjustment
- Punctuation width and position fine-tuning
- Proper line breaking with forbidden positions
- Character pair kerning for professional spacing
縦書きの小説ビューアに最適:
VerticalText(
'吾輩は猫である。名前はまだ無い。'
'どこで生まれたかとんと見当がつかぬ。',
style: VerticalTextStyle(
baseStyle: TextStyle(
fontSize: 18,
fontFamily: 'NotoSerifJP', // 明朝体推奨
height: 1.8,
),
lineSpacing: 24,
characterSpacing: 2,
),
maxHeight: 500,
)一行で表示する短詩形式:
VerticalText(
'古池や蛙飛び込む水の音',
ruby: const [
RubyText(startIndex: 0, length: 2, ruby: 'ふるいけ'),
RubyText(startIndex: 3, length: 1, ruby: 'かわず'),
],
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 28),
rubyStyle: TextStyle(fontSize: 12),
characterSpacing: 8,
),
)見出しと本文の組み合わせ:
Column(
children: [
VerticalText(
'本日の主要ニュース',
style: const VerticalTextStyle(
baseStyle: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
),
),
),
VerticalText(
'詳細な本文がここに続きます...',
kenten: const [
Kenten(startIndex: 0, length: 2, style: KentenStyle.sesame),
],
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 16),
lineSpacing: 16,
),
maxHeight: 300,
),
],
)日付に縦中横を使用:
VerticalText(
'令和07年01月01日 謹賀新年',
autoTatechuyoko: true, // 07, 01 が横組みに
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 24),
characterSpacing: 4,
),
)選択可能なテキストで読解練習:
SelectableVerticalText(
'漢字の読み方を学びましょう。',
ruby: const [
RubyText(startIndex: 0, length: 2, ruby: 'かんじ'),
RubyText(startIndex: 3, length: 2, ruby: 'よみかた'),
],
style: const VerticalTextStyle(
baseStyle: TextStyle(fontSize: 28),
rubyStyle: TextStyle(fontSize: 14, color: Colors.blue),
),
maxHeight: 400,
)tategaki v0.2.0+ includes significant performance optimizations:
- TextPainter Reuse: Reduced memory allocations by reusing TextPainter instances across renders
- Efficient Layout: Character layout caching for optimal performance
- Lazy Rendering: CustomPainter-based rendering with minimal overhead
- Memory Efficient: Low memory footprint even for long vertical texts
Performance improvements in v0.2.0:
- ~50% reduction in TextPainter allocations
- Improved rendering performance for scrollable vertical text lists
- Reduced memory pressure during text rendering
- Basic vertical text layout
- Ruby (furigana) support
- Kenten (emphasis dots) support
- Tatechuyoko (horizontal in vertical)
- Advanced kinsoku processing
- Professional kerning
- Advanced yakumono adjustment
- RichText support with multiple styles
- Comprehensive unit tests
- Performance optimizations (v0.2.0)
- Text selection with context menu (v0.3.0)
- Text alignment (地付き/天付き) (v0.4.0)
- Text decoration (sideline) support
- Selection API integration (SelectionArea support)
- Long press selectable text (v0.6.5)
- Text editing support (planned)
- PDF export (planned)
- Web optimization (planned)
Contributions are welcome! Please feel free to submit issues or pull requests.
git clone https://github.com/youichi-uda/tategaki.git
cd tategaki
flutter pub get
flutter testMIT License - see the LICENSE file for details.
Created by Youichi Uda
Special thanks to the Flutter community and the W3C Japanese Layout Task Force for their comprehensive documentation on Japanese typography.
- W3C Japanese Text Layout Requirements
- JIS X 4051:2004 - Japanese document composition method
- Flutter CustomPainter