dailytags
Comprehensive guide for using DailyTags - a Jetpack Compose markdown library that supports custom tags. Use this skill when working with markdown rendering, custom markup, rich text formatting in Compose, or creating pattern-based text parsers for Android applications. DailyTags parses text into nodes styled with AnnotatedString, providing a WebView-free solution for rendering markdown and HTML with full customization support.
What this skill does
# DailyTags Skill
## Overview
DailyTags is a flexible markdown library for Jetpack Compose that parses markup into rich text using AnnotatedString. It's lightweight (<50kb), fast, extensible, and requires no WebView.
**Key Capabilities:**
- ✅ Markdown parsing with built-in rules
- ✅ HTML support with built-in rules
- ✅ Custom tag/markup creation via regex patterns
- ✅ Full styling control (SpanStyle, ParagraphStyle)
- ✅ Node-based parsing architecture
- ✅ Native Compose integration
**Important Limitation:**
- ⚠️ **Text content only** - Cannot render images, tables, checkboxes, or custom UI elements
- For non-text elements, use hybrid approach with regular Compose components
## Installation
### Gradle Setup
Add JitPack repository to your root `build.gradle`:
```gradle
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
```
Add dependency to your module `build.gradle`:
```gradle
dependencies {
implementation "com.github.DmytroShuba:DailyTags:1.0.0"
}
```
**Current Version:** 1.0.0 (February 2022)
**Min API Level:** 23+
**License:** MIT
## Core Architecture
### Parsing Flow
```
Source Text → Rules → Parser → Nodes → Render → AnnotatedString → Text Composable
```
### Key Components
1. **SimpleMarkupParser**: Main parsing engine that processes text using rules
2. **Rules**: Pattern-based definitions for how to extract and style content
3. **Nodes**: Internal representation of parsed elements
4. **AnnotatedString**: Compose's rich text format (final output)
## Basic Usage
### 1. Simple Markdown Rendering
```kotlin
import com.dmytroshuba.dailytags.markdown.rules.MarkdownRules
import com.dmytroshuba.dailytags.core.simple.SimpleMarkupParser
import com.dmytroshuba.dailytags.core.simple.render
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@Composable
fun MarkdownText(source: String) {
val parser = SimpleMarkupParser()
val rules = MarkdownRules.toList()
val content = parser
.parse(source, rules)
.render()
.toAnnotatedString()
Text(text = content)
}
// Usage
MarkdownText("**Bold text** and *italic text*")
```
### 2. Markdown + HTML Combined
```kotlin
import com.dmytroshuba.dailytags.markdown.rules.HtmlRules
@Composable
fun RichText(source: String) {
val parser = SimpleMarkupParser()
val rules = MarkdownRules.toList() + HtmlRules.toList()
val content = parser
.parse(source, rules)
.render()
.toAnnotatedString()
Text(text = content)
}
// Usage
RichText("""
<b>HTML bold</b> and **Markdown bold**
<i>HTML italic</i> and *Markdown italic*
""")
```
## Custom Tags & Markup
### Creating Custom Rules
#### Step 1: Define Pattern
Use Java's `Pattern` class to create regex patterns:
```kotlin
import java.util.regex.Pattern
// Highlight tag: <hl-blue>text</hl-blue>
val PATTERN_HIGHLIGHT_BLUE = Pattern.compile("^<hl-blue>([\\s\\S]+?)<\\/hl-blue>")
// Spoiler tag: ||hidden text||
val PATTERN_SPOILER = Pattern.compile("^\\|\\|([\\s\\S]+?)\\|\\|")
// Mention tag: @username
val PATTERN_MENTION = Pattern.compile("^@([a-zA-Z0-9_]+)")
// Code language tag: ```kotlin code ```
val PATTERN_CODE_BLOCK = Pattern.compile("^```(\\w+)\\n([\\s\\S]+?)```")
```
#### Step 2: Convert Pattern to Rule
Use the `toRule()` extension function:
```kotlin
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import com.dmytroshuba.dailytags.core.simple.toRule
// Basic styling
val blueHighlightRule = PATTERN_HIGHLIGHT_BLUE.toRule(
spanStyle = SpanStyle(
color = Color.Blue,
background = Color.Blue.copy(alpha = 0.1f)
)
)
// Complex styling with multiple properties
val spoilerRule = PATTERN_SPOILER.toRule(
spanStyle = SpanStyle(
color = Color.Black,
background = Color.DarkGray
)
)
val mentionRule = PATTERN_MENTION.toRule(
spanStyle = SpanStyle(
color = Color(0xFF1DA1F2), // Twitter blue
fontWeight = FontWeight.Bold
)
)
```
#### Step 3: Use Custom Rules
```kotlin
@Composable
fun CustomMarkupText(source: String) {
val parser = SimpleMarkupParser()
// Combine built-in and custom rules
val rules = MarkdownRules.toList() + listOf(
blueHighlightRule,
spoilerRule,
mentionRule
)
val content = parser
.parse(source, rules)
.render()
.toAnnotatedString()
Text(text = content)
}
// Usage
CustomMarkupText("""
Regular text with <hl-blue>blue highlight</hl-blue>
This is a ||spoiler||
Hey @username, check this out!
""")
```
## Advanced Patterns
### 1. Paragraph Styling
```kotlin
import androidx.compose.ui.text.ParagraphStyle
import androidx.compose.ui.unit.sp
import androidx.compose.ui.text.style.TextIndent
val PATTERN_QUOTE = Pattern.compile("^> (.+)$", Pattern.MULTILINE)
val quoteRule = PATTERN_QUOTE.toRule(
spanStyle = SpanStyle(
color = Color.Gray,
fontStyle = FontStyle.Italic
),
paragraphStyle = ParagraphStyle(
textIndent = TextIndent(firstLine = 16.sp),
lineHeight = 20.sp
)
)
```
### 2. Multi-Group Patterns
Extract and style different groups separately:
```kotlin
// Pattern with capturing groups
val PATTERN_LINK = Pattern.compile("^\\[([^\\]]+)\\]\\(([^)]+)\\)")
// Custom rendering with different styles for text and URL
val linkRule = PATTERN_LINK.toRule(
spanStyle = SpanStyle(
color = Color.Blue,
textDecoration = TextDecoration.Underline
)
)
```
### 3. Nested Rules
Rules are processed in order, allowing nested markup:
```kotlin
val rules = listOf(
// Process outer tags first
blockquoteRule,
// Then inner formatting
boldRule,
italicRule,
codeRule
)
```
### 4. Conditional Styling
Create rules that apply different styles based on content:
```kotlin
val PATTERN_TAG = Pattern.compile("^#(\\w+)")
fun createTagRule(color: Color) = PATTERN_TAG.toRule(
spanStyle = SpanStyle(
color = color,
fontWeight = FontWeight.Medium,
background = color.copy(alpha = 0.1f)
)
)
// Usage with different colors
val tagRules = listOf(
createTagRule(Color.Red),
createTagRule(Color.Blue),
createTagRule(Color.Green)
)
```
## Important Limitations
**DailyTags works with TEXT CONTENT ONLY.** It cannot render:
- ❌ Images (including `` and `<img>` tags)
- ❌ Tables
- ❌ Checkboxes / Task lists
- ❌ Custom UI elements
- ❌ Embedded media (video, audio)
- ❌ Interactive widgets
**What this means:**
- Image syntax like `` will be parsed but NOT display an image
- Table markdown will be treated as plain text
- Checkbox syntax `- [ ]` will render as text, not interactive checkboxes
- Only text styling (bold, italic, color, etc.) is supported
**For these features, you need to:**
- Use regular Compose Image() composables separately
- Build custom UI components outside DailyTags
- Consider hybrid approaches (DailyTags for text, Compose for UI elements)
## Supported Markdown Features
### Text Formatting
- **Bold**: `**text**` or `__text__`
- *Italic*: `*text*` or `_text_`
- ~~Strikethrough~~: `~~text~~`
- `Inline code`: `` `code` ``
- Combined: `***bold italic***`
### Headings
```markdown
# H1 Heading
## H2 Heading
### H3 Heading
#### H4 Heading
##### H5 Heading
###### H6 Heading
```
### Lists
```markdown
- Unordered list item 1
- Unordered list item 2
- Nested item
1. Ordered list item 1
2. Ordered list item 2
1. Nested numbered item
```
### Links and Images (Text Only)
**Links:**
```markdown
[Link text](https://example.com)
```
Note: Links are styled but not clickable by default. Use ClickableText for interactivity.
**Images:**
```markdown

```
⚠️ **Important:** Image markdown is parsed as text only - no actual image rendering. You'll see the alt text,Related in Web Dev
generating-lwc-components
IncludedLightning Web Components with PICKLES methodology and 165-point scoring. Use this skill when the user creates or edits LWC components, builds wire service patterns, or writes Jest tests for LWC. TRIGGER when: user creates/edits LWC components, touches lwc/**/*.js, .html, .css, .js-meta.xml files, or asks about wire service, SLDS, or Jest LWC tests. DO NOT TRIGGER when: Apex classes (use generating-apex), Aura components, or Visualforce.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Set up queries with useQuery, mutations with useMutation, configure QueryClient caching strategies, implement optimistic updates, and handle infinite scroll with useInfiniteQuery. Use when: setting up data fetching in React projects, migrating from v4 to v5, or fixing object syntax required errors, query callbacks removed issues, cacheTime renamed to gcTime, isPending vs isLoading confusion, keepPreviousData removed problems.
document-processor-api
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
nutrient-document-processing
IncludedProcess documents with Nutrient DWS. Use when the user wants to generate PDFs from HTML or URLs, convert Office/images/PDFs, assemble or split packets, OCR scans, extract text/tables/key-value pairs, redact PII, watermark, sign, fill forms, optimize PDFs, or produce compliance outputs like PDF/A or PDF/UA. Triggers include convert to PDF, merge these PDFs, OCR this scan, extract tables, redact PII, sign this PDF, make this PDF/A, or linearize for web delivery.
tanstack-query
IncludedManage server state in React with TanStack Query v5. Covers useMutationState, simplified optimistic updates, throwOnError, network mode (offline/PWA), and infiniteQueryOptions. Use when setting up data fetching, fixing v4→v5 migration errors (object syntax, gcTime, isPending, keepPreviousData), or debugging SSR/hydration issues with streaming server components.
accelint-nextjs-best-practices
IncludedNext.js performance optimization and best practices. Use when writing Next.js code (App Router or Pages Router); implementing Server Components, Server Actions, or API routes; optimizing RSC serialization, data fetching, or server-side rendering; reviewing Next.js code for performance issues; fixing authentication in Server Actions; or implementing Suspense boundaries, parallel data fetching, or request deduplication.