Props
Props (Properties) are the inputs to components, used to configure component behavior and appearance. This guide will detail how to use props in Purepy.
What are Props?
Props are data passed to components, typically as a dictionary. Components receive external data through props and render corresponding content based on this data.
Basic Props Usage
Passing Props
from pure.html import div, h1, p
def Greeting(props):
name = props.get('name', 'Guest')
message = props.get('message', 'Welcome!')
return div(
h1(f'Hello, {name}!'),
p(message)
).class_name('greeting')
# Use component and pass props
greeting = Greeting({
'name': 'John',
'message': 'Welcome to our website!'
})Props Types
Props can be any Python data type:
def UserCard(props):
# String props
name = props.get('name', '')
# Number props
age = props.get('age', 0)
# Boolean props
is_premium = props.get('isPremium', False)
# List props
hobbies = props.get('hobbies', [])
# Dictionary props
address = props.get('address', {})
return div(
h2(name),
p(f'Age: {age}'),
p('Premium User' if is_premium else 'Regular User'),
div(
h3('Hobbies:'),
ul(*[li(hobby) for hobby in hobbies])
) if hobbies else None,
div(
h3('Address:'),
p(f"{address.get('city', '')} {address.get('street', '')}")
) if address else None
).class_name('user-card')Default Props
Provide default values for props to make components more robust:
from pure.html import button, div, h2, p
def Button(props):
# Use get() method to provide default values
text = props.get('text', 'Button')
variant = props.get('variant', 'primary')
size = props.get('size', 'medium')
disabled = props.get('disabled', False)
return button(text) \
.class_name(f'btn btn-{variant} btn-{size}') \
.disabled(disabled)
# You can also use dictionary merging
def Card(props):
defaults = {
'title': 'Default Title',
'content': 'Default Content',
'variant': 'default',
'shadow': True
}
# Merge defaults with passed props
merged_props = {**defaults, **props}
return div(
h2(merged_props['title']),
p(merged_props['content'])
).class_name(f"card card-{merged_props['variant']}" +
(' card-shadow' if merged_props['shadow'] else ''))Props Validation
While Python is dynamically typed, we can add props validation to improve code quality:
def validateProps(props, required=None, types=None):
"""Simple props validation function"""
required = required or []
types = types or {}
# Check required props
for prop in required:
if prop not in props:
raise ValueError(f"Missing required prop: {prop}")
# Check prop types
for prop, expected_type in types.items():
if prop in props and not isinstance(props[prop], expected_type):
raise TypeError(f"Prop {prop} should be of type {expected_type.__name__}")
def SafeButton(props):
# Validate props
validateProps(props,
required=['text'],
types={'text': str, 'disabled': bool})
return button(props['text']) \
.class_name('btn') \
.disabled(props.get('disabled', False))Props Passing Patterns
1. Props Pass-through
Pass props to child components:
def Card(props):
# Extract card-specific props
title = props.get('title', '')
content = props.get('content', '')
# Pass button-related props to Button component
button_props = {
'text': props.get('buttonText', 'Learn More'),
'variant': props.get('buttonVariant', 'primary'),
'disabled': props.get('buttonDisabled', False)
}
return div(
h2(title),
p(content),
Button(button_props)
).class_name('card')2. Props Destructuring
Extract specific values from props:
def UserProfile(props):
user = props.get('user', {})
# Destructure user object
name = user.get('name', '')
email = user.get('email', '')
avatar = user.get('avatar', '')
bio = user.get('bio', '')
return div(
div(
img().src(avatar).alt(name) if avatar else None,
h2(name),
p(email)
).class_name('user-header'),
div(
p(bio)
).class_name('user-bio') if bio else None
).class_name('user-profile')3. Props Grouping
Group related props for passing:
def Form(props):
# Form configuration
form_config = props.get('config', {})
# Field definitions
fields = props.get('fields', [])
# Submit configuration
submit_config = props.get('submit', {})
return form(
*[FormField(field) for field in fields],
button(submit_config.get('text', 'Submit')) \
.type('submit') \
.class_name(submit_config.get('className', 'btn btn-primary'))
) \
.action(form_config.get('action', '')) \
.method(form_config.get('method', 'post')) \
.class_name(form_config.get('className', 'form'))Conditional Props
Set different props based on conditions:
def Alert(props):
alert_type = props.get('type', 'info')
message = props.get('message', '')
dismissible = props.get('dismissible', False)
# Set different icons based on type
icons = {
'info': 'ℹ️',
'success': '✅',
'warning': '⚠️',
'error': '❌'
}
icon = icons.get(alert_type, icons['info'])
return div(
span(icon).class_name('alert-icon'),
span(message).class_name('alert-message'),
button('×').class_name('alert-close') if dismissible else None
).class_name(f'alert alert-{alert_type}')Function Props
While not commonly used when generating static HTML, you can pass functions as props:
def DataTable(props):
data = props.get('data', [])
columns = props.get('columns', [])
row_renderer = props.get('rowRenderer', None)
def default_row_renderer(row, index):
return tr(
*[td(str(row.get(col['key'], ''))) for col in columns]
)
renderer = row_renderer or default_row_renderer
return table(
thead(
tr(*[th(col['title']) for col in columns])
),
tbody(
*[renderer(row, i) for i, row in enumerate(data)]
)
).class_name('data-table')
# Use custom renderer
def custom_row_renderer(row, index):
return tr(
td(row.get('name', '')),
td(row.get('email', '')),
td(
button('Edit').class_name('btn btn-sm'),
button('Delete').class_name('btn btn-sm btn-danger')
)
).class_name('table-row')
table = DataTable({
'data': users,
'columns': [
{'key': 'name', 'title': 'Name'},
{'key': 'email', 'title': 'Email'},
{'key': 'actions', 'title': 'Actions'}
],
'rowRenderer': custom_row_renderer
})Props Best Practices
1. Use Descriptive Prop Names
# Bad naming
def Card(props):
t = props.get('t') # Unclear what 't' is
c = props.get('c') # Unclear what 'c' is
# Good naming
def Card(props):
title = props.get('title')
content = props.get('content')2. Keep Props Structure Simple
# Avoid over-nesting
# Bad practice
props = {
'user': {
'profile': {
'personal': {
'name': {
'first': 'John',
'last': 'Doe'
}
}
}
}
}
# Good practice
props = {
'firstName': 'John',
'lastName': 'Doe',
'email': 'john@example.com'
}3. Use Type Hints
from typing import Dict, Any, List, Optional
def UserList(props: Dict[str, Any]) -> 'HTML':
users: List[Dict[str, Any]] = props.get('users', [])
title: str = props.get('title', 'User List')
show_email: bool = props.get('showEmail', True)
return div(
h2(title),
ul(
*[UserItem({
'user': user,
'showEmail': show_email
}) for user in users]
)
).class_name('user-list')4. Document Props
def Button(props):
"""
Button component
Props:
text (str): Button text, defaults to 'Button'
variant (str): Button style, options: 'primary', 'secondary', 'danger'
size (str): Button size, options: 'small', 'medium', 'large'
disabled (bool): Whether disabled, defaults to False
fullWidth (bool): Whether full width, defaults to False
onClick (str): Click event handler
"""
# Component implementation...Props Pattern Examples
Configuration Object Pattern
def Chart(props):
config = props.get('config', {})
data = props.get('data', [])
# Extract settings from config
chart_type = config.get('type', 'bar')
width = config.get('width', 400)
height = config.get('height', 300)
colors = config.get('colors', ['#blue', '#red', '#green'])
return div(
# Chart implementation...
).class_name(f'chart chart-{chart_type}') \
.style(f'width: {width}px; height: {height}px;')Render Props Pattern
def List(props):
items = props.get('items', [])
render_item = props.get('renderItem', None)
def default_render(item, index):
return li(str(item))
renderer = render_item or default_render
return ul(
*[renderer(item, i) for i, item in enumerate(items)]
).class_name('list')Next Steps
Now that you've mastered using props, you can continue learning:
- TailwindCSS Integration - Learn how to style components
- API Reference - View complete API documentation
- Basic Usage - Review basic syntax