Components
Card
Card is a rounded surface that groups related content. It can have a header above the content and a footer below
it. The header, the content and the footer are your JSX; the card adds the surface, the padding and the divider.
// Card: elevated and outlined, with a header and a footer slot.
import { mount, Scroll, signal, Text, View } from "nsh";
import { Button, Card } from "nsh/ui/mobile";
function App() {
const likes = signal(0);
return (
<Scroll style={{ flex: 1, backgroundColor: "#ffffff" }}>
<View style={{ padding: 16, paddingTop: 24, gap: 16 }}>
<Text style={{ fontSize: 22, fontWeight: "700" }}>Card</Text>
<Card
header={<Text>Weekly summary</Text>}
footer={
<View style={{ flexDirection: "row", gap: 8 }}>
<Button title="Reset" variant="plain" onPress={() => likes.set(0)} />
<Button title={`Like (${likes()})`} onPress={() => likes.set(likes() + 1)} />
</View>
}
>
<Text>You walked 42 km this week, 8 km more than last week.</Text>
<Text style={{ color: "#737373" }}>The header, this body and the footer are the app's JSX.</Text>
</Card>
<Card variant="outlined">
<Text style={{ fontWeight: "600" }}>Outlined</Text>
<Text>A border, no shadow, and no header or footer: only children.</Text>
</Card>
<Card
variant="outlined"
header={
<View style={{ flexDirection: "row", alignItems: "center", gap: 10 }}>
<View style={{ width: 32, height: 32, borderRadius: 16, backgroundColor: "#a78bfa" }} />
<Text>Ada Lovelace</Text>
</View>
}
>
<Text>A header can be any row, such as an avatar and a name.</Text>
</Card>
</View>
</Scroll>
);
}
mount(App);import { Card } from "nsh/ui/mobile";
#Usage
import { mount, Text, View } from "nsh";
import { Button, Card } from "nsh/ui/mobile";
function App() {
return (
<View style={{ flex: 1, padding: 16, paddingTop: 48 }}>
<Card
header={<Text>Weekly summary</Text>}
footer={<Button title="Details" variant="plain" onPress={() => console.log("details")} />}
>
<Text>You walked 42 km this week.</Text>
<Text>That is 8 km more than last week.</Text>
</Card>
</View>
);
}
mount(App);
#Layout
- Header: 16 pt padding at the sides and the top. Text in the header is semibold and 1 pt larger than the theme’s
font.size, so a plain<Text>works as a title. A header can be any JSX, for example an avatar and a name in a row. - Content: the children are stacked in a column with 8 pt gaps. With a header, the content has 8 pt padding at the top and 16 pt at the sides and the bottom. Without a header, it has 16 pt padding on all sides.
- Footer: a row aligned to the end, with 8 pt gaps, 16 pt horizontal and 12 pt vertical padding, and a divider above it. Put actions here.
<Card
variant="outlined"
header={
<View style={{ flexDirection: "row", alignItems: "center", gap: 10 }}>
<View style={{ width: 32, height: 32, borderRadius: 16, backgroundColor: "#a78bfa" }} />
<Text>Ada Lovelace</Text>
</View>
}
footer={
<View style={{ flexDirection: "row", gap: 8 }}>
<Button title="Ignore" variant="plain" onPress={ignore} />
<Button title="Reply" onPress={reply} />
</View>
}
>
<Text>Can we move the meeting to Thursday?</Text>
</Card>
The header and footer only exist while you pass them: header={cond() ? <Text>…</Text> : undefined} adds and
removes the header, and the content’s padding changes to match.
#Variants
| Variant | Look |
|---|---|
elevated (default) | A 1 pt border and a small shadow. |
outlined | A 1 pt border, no shadow. |
<Card>…</Card>
<Card variant="outlined">…</Card>
#Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "elevated" | "outlined" | "elevated" | Whether the card has a shadow. |
header | JSX.Element | none | Above the content: a title or an avatar row. Its text is semibold. |
footer | JSX.Element | none | Below the content, after a divider: actions, aligned to the end. |
children | JSX.Element | none | The content. |
class, classList, style, testID, onLayout, ref | Applied to the card’s root view. class and style override the card’s own styles. |
Card has no events. Put handlers on your own content.
#Theming
| Part | Theme key |
|---|---|
| Surface | group_box.background |
| Text color (inherited by the content) | group_box.foreground |
| Border and footer divider | border |
| Corner radius | radius.lg (16 pt by default) |
| Header text size | font.size + 1 |
See Theming.
#Accessibility
The card adds no role or label. Screen readers read the header, content and footer in order, as separate elements.