Customization¶
Language label¶
The language label is a composable slot - replace it with any @Composable:
import dev.hossain.highlight.ui.SyntaxHighlightedCode
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
languageLabel = {
Text(
text = "Kotlin",
color = Color.White,
fontSize = 11.sp,
modifier = Modifier
.background(Color(0xFF7F52FF), RoundedCornerShape(4.dp))
.padding(horizontal = 6.dp, vertical = 2.dp),
)
},
)
Pass null to hide the label entirely:
import dev.hossain.highlight.ui.SyntaxHighlightedCode
SyntaxHighlightedCode(code = snippet, language = "kotlin", languageLabel = null)
Toggle the default label at runtime¶
Use SyntaxHighlightedCodeDefaults.LanguageLabel to keep the default look while
toggling visibility - no need to reconstruct the styling yourself:
import dev.hossain.highlight.ui.SyntaxHighlightedCode
import dev.hossain.highlight.ui.SyntaxHighlightedCodeDefaults
var showLabel by remember { mutableStateOf(true) }
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
languageLabel = if (showLabel) {
{ SyntaxHighlightedCodeDefaults.LanguageLabel("kotlin") }
} else null,
)
Header actions¶
The actions slot runs with a RowScope receiver and provides a pre-wired onCopy action.
Use it to provide custom trailing buttons, multiple actions, or hide trailing actions.
Custom copy icon¶
The icon examples below use Icons.Default.*, which needs the Material icons artifact (Material 3 does not
include it): implementation("androidx.compose.material:material-icons-extended").
import dev.hossain.highlight.ui.SyntaxHighlightedCode
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
actions = { onCopy ->
IconButton(onClick = onCopy) {
Icon(Icons.Default.ContentCopy, contentDescription = "Copy code")
}
},
)
Multiple action buttons¶
Because actions runs within a RowScope, multiple action buttons lay out horizontally without requiring a custom Row:
import dev.hossain.highlight.ui.SyntaxHighlightedCode
import dev.hossain.highlight.ui.SyntaxHighlightedCodeDefaults
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
actions = { onCopy ->
IconButton(onClick = onEdit) {
Icon(Icons.Default.Edit, contentDescription = "Edit code")
}
IconButton(onClick = onShare) {
Icon(Icons.Default.Share, contentDescription = "Share code")
}
SyntaxHighlightedCodeDefaults.CopyButton(onClick = onCopy)
},
)
Hide trailing actions¶
Pass null to actions to hide all trailing actions (including the default copy button) while keeping the language label:
import dev.hossain.highlight.ui.SyntaxHighlightedCode
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
actions = null,
)
Custom copy feedback (Snackbar, Toast, etc.)¶
import dev.hossain.highlight.ui.SyntaxHighlightedCode
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
val clipboard = LocalClipboard.current
Scaffold(snackbarHost = { SnackbarHost(snackbarHostState) }) { padding ->
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
modifier = Modifier.padding(padding),
onCopyClick = { copiedText ->
scope.launch {
// onCopyClick replaces the built-in copy, so copy explicitly
clipboard.setClipEntry(ClipEntry(ClipData.newPlainText("code", copiedText)))
snackbarHostState.showSnackbar("Copied!")
}
},
)
}
Note
When onCopyClick is null (the default), the button copies to the system clipboard automatically. A non-null onCopyClick replaces that built-in copy, so write to the clipboard yourself (as above) if you still want the code copied.
Adjust copy button touch target¶
import dev.hossain.highlight.ui.CodeBlockStyle
import dev.hossain.highlight.ui.SyntaxHighlightedCode
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
style = CodeBlockStyle(copyButtonSize = 48.dp),
)
Custom header chrome¶
Use the coarse-grained header slot to replace the entire header row inside the card (for example, with a file
title bar, IDE tabs, or custom background):
import dev.hossain.highlight.ui.SyntaxHighlightedCode
import dev.hossain.highlight.ui.SyntaxHighlightedCodeDefaults
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
header = { onCopy ->
Row(
modifier = Modifier
.fillMaxWidth()
.background(Color(0xFF2D2D2D))
.padding(horizontal = 12.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text("MainActivity.kt", color = Color.White, fontWeight = FontWeight.Bold)
Spacer(modifier = Modifier.weight(1f))
SyntaxHighlightedCodeDefaults.CopyButton(onClick = onCopy, tint = Color.White)
}
},
)
When header is provided, languageLabel and actions are ignored.
Headerless mode¶
Pass header = null to omit the header row completely in a single parameter:
import dev.hossain.highlight.ui.SyntaxHighlightedCode
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
header = null,
)
Block shape and padding¶
import dev.hossain.highlight.ui.CodeBlockStyle
import dev.hossain.highlight.ui.SyntaxHighlightedCode
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
style = CodeBlockStyle(
shape = RoundedCornerShape(4.dp),
padding = PaddingValues(horizontal = 12.dp, vertical = 8.dp),
headerPadding = PaddingValues(horizontal = 12.dp, vertical = 4.dp),
),
)
Custom font¶
import dev.hossain.highlight.ui.CodeBlockStyle
import dev.hossain.highlight.ui.SyntaxHighlightedCode
import dev.hossain.highlight.ui.SyntaxHighlightedCodeDefaults
// Top-level so the FontFamily is not re-created on every recomposition
private val firaCode = FontFamily(Font(R.font.fira_code))
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
style = CodeBlockStyle(
textStyle = SyntaxHighlightedCodeDefaults.codeTextStyle.copy(
fontFamily = firaCode,
fontSize = 14.sp,
),
),
)
Line number styling¶
import dev.hossain.highlight.ui.CodeBlockStyle
import dev.hossain.highlight.ui.SyntaxHighlightedCode
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
showLineNumbers = true,
style = CodeBlockStyle(
lineNumberWidth = 40.dp,
lineNumberColor = Color(0xFF888888),
),
)
Compose modifier¶
Apply any modifier to the outer container:
import dev.hossain.highlight.ui.SyntaxHighlightedCode
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
modifier = Modifier
.fillMaxWidth()
.heightIn(max = 300.dp)
.verticalScroll(rememberScrollState()),
)
Accessibility¶
The code text is fully selectable (via SelectionContainer) and the copy button uses contentDescription for accessibility. To provide a localized description:
import dev.hossain.highlight.ui.SyntaxHighlightedCode
import dev.hossain.highlight.ui.SyntaxHighlightedCodeDefaults
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
actions = { onCopy ->
SyntaxHighlightedCodeDefaults.CopyButton(
onClick = onCopy,
contentDescription = stringResource(R.string.copy_code_a11y),
)
},
)
Fallback background and text colors¶
When you use a custom HighlightTheme (via fromAsset() or fromCss()) whose CSS omits the
base .hljs { background: ...; color: ... } rule, the block would otherwise render with a
transparent background and invisible text. Override the two fallback parameters on CodeBlockStyle
to control what is shown in that case:
import dev.hossain.highlight.ui.CodeBlockStyle
import dev.hossain.highlight.ui.SyntaxHighlightedCode
SyntaxHighlightedCode(
code = snippet,
language = "kotlin",
style = CodeBlockStyle(
fallbackBackgroundColor = Color(0xFF0D1117),
fallbackTextColor = Color(0xFFC9D1D9),
),
)
Note
Built-in themes (Tomorrow, Atom One, GitHub, Dracula, Alucard) always include a full
.hljs rule, so these fallback colors have no visible effect when using them.