pug Template
The pug template literal lets you write JSX using Pug syntax. This is optional — CSSX works great with standard JSX.
In CSSX 0.3, Pug templates also support TypeScript syntax in TSX files and can contain a terminal embedded style block:
style(lang='styl') for Stylus
style for plain CSS
For components written in Pug, embedded styles are the preferred way to colocate local styles.
Basic Usage
import { pug } from 'cssxjs'
import { View, Text } from 'react-native'
function Card({ title, children }) {
return pug`
View.card
Text.title= title
View.content
= children
style(lang='styl')
.card
background white
border-radius 8px
.title
font-size 18px
.content
padding 16px
`
}
Why Pug?
Pug offers a concise, indentation-based syntax:
// JSX
<View styleName="container">
<View styleName="header">
<Text styleName="title">Hello</Text>
</View>
</View>
// Pug
View.container
View.header
Text.title Hello
Embedded Style Blocks
Embedded style blocks are written as the last top-level node in a pug template.
Stylus
return pug`
Pressable.button(onPress=onPress)
Text.text= children
style(lang='styl')
.button
padding 12px 16px
border-radius 6px
background #1677ff
.text
color white
`
CSS
return pug`
View.card
Text.title CSS syntax
style
.card {
padding: 16px;
border-radius: 8px;
background: white;
}
.title {
font-size: 18px;
}
`
The transform moves the embedded style block into the immediate enclosing scope as a styl or css template literal. Standalone styl and css template literals remain supported for JSX components and shared module-level styles.
TypeScript
Pug templates in TSX files support TypeScript expressions. Use npx cssxjs check for Pug-aware type checks, because tsc --noEmit does not type-check expressions inside Pug template strings.
See TypeScript Support for the full guide.
Class Names
Class names (.className) become the styleName prop:
View.button.primary
// -> <View styleName="button primary" />
View.card.featured.large
// -> <View styleName="card featured large" />
Dynamic Classes
// Array with object for modifiers
View.button(styleName=[variant, { active, disabled }])
// -> <View styleName={['button', variant, { active, disabled }]} />
// Object syntax
View.button(styleName={ active, disabled })
// -> <View styleName={['button', { active, disabled }]} />
Attributes
Pass attributes in parentheses:
// Static
Pressable.btn(disabled)
Text Submit
// Dynamic
TextInput.input(value=inputValue onChangeText=handleChange)
// Spread
View.wrapper(...props)
// Part attribute
View.root(part="root")
Content
Text Content
Text.title= title // Variable
Text.text Hello World // Static text
Text.count #{count} items // Inline interpolation
Children
function Wrapper({ children }) {
return pug`
View.wrapper
= children
`
}
Control Flow
Conditionals
pug`
View.container
if isLoggedIn
Text.user= userName
else
Pressable.login
Text Login
`
Loops
pug`
View.list
each item in items
View.item(key=item.id)
Text= item.name
`
Components
Use PascalCase for components:
import { pug } from 'cssxjs'
import { View, Text } from 'react-native'
import { Card } from './Card'
import { Button } from './Button'
function App() {
return pug`
View.app
Card.featured(title="Welcome")
Text This is content
Button.primary(onPress=handlePress) Click Me
`
}
Complete Example
import { pug } from 'cssxjs'
import { View, Text, Image, Pressable } from 'react-native'
function UserProfile({ user, isOnline, onLogout }) {
return pug`
View.root(part="root")
View.header(part="header")
Image.avatar(source={ uri: user.avatar })
View.info
Text.name= user.name
if isOnline
Text.status.online Online
else
Text.status.offline Offline
View.content(part="content")
Text.bio= user.bio
View.actions
Pressable.button.secondary(onPress=onLogout)
Text.buttonText Logout
style(lang='styl')
.root
background white
border-radius 12px
.header
flex-direction row
align-items center
gap 16px
padding 20px
.avatar
width 64px
height 64px
border-radius 32px
.name
font-size 20px
.status
font-size 12px
padding 2px 8px
border-radius 10px
overflow hidden
&.online
background #4caf50
color white
&.offline
background #9e9e9e
color white
.content
padding 20px
.actions
padding 16px 20px
border-top-width 1px
border-top-color #eee
.button
padding 8px 16px
border-radius 6px
&.secondary
background #f5f5f5
.buttonText
color #333
`
}
Mixing JSX and Pug
You can use both in the same file:
import { pug } from 'cssxjs'
import { View } from 'react-native'
function App({ children }) {
// JSX for complex logic
const header = (
<View>
<Navigation items={navItems} />
</View>
)
// Pug for simpler structure
return pug`
View.app
= header
View.content
= children
`
}
Disabling Pug
If you don't use Pug, disable it for faster builds:
// babel.config.js
['cssxjs/babel', {
transformPug: false
}]
Quick Reference
See Also