Skip to content

Patterns

How the components combine into jsonresume.org pages.

Page anatomy

Yellow header, gray title band, white content, alternating bands, quiet footer.

page structure
<SkipLink />
<SiteHeader brand={<Logo />}>…</SiteHeader>
<main id="main">
  <PageHeader title="Themes" description="…" />
  <Section>
    <Container>…content…</Container>
  </Section>
  <Section tone="subtle">
    <Container>…related content…</Container>
  </Section>
</main>
<SiteFooter links={[…]} />

Landing page

A Hero followed by a row of Features on a gray band.

Hero

JSON Resume

The open-source initiative to create a JSON-based standard for resumes. For developers, by developers.

hero/promo.tsx
import { Button, Hero } from '@jsonresume/ui';

export default function HeroPromo() {
  return (
    <Hero
      title="JSON Resume"
      lede="The open-source initiative to create a JSON-based standard for resumes. For developers, by developers."
      actions={
        <Button variant="primary" size="lg">
          Read more
        </Button>
      }
    />
  );
}
Feature row

What is this?

JSON Resume is a standard created to empower developers.

Themes

Browse our gallery of resume themes made by the community.

Open Source

Every part of JSON Resume is open source on GitHub.
feature/row.tsx
import { Button, Container, Feature, Grid, Section } from '@jsonresume/ui';

export default function FeatureRow() {
  return (
    <Section tone="subtle">
      <Container>
        <Grid minColumnWidth="14rem" gap={8}>
          <Feature title="What is this?" action={<Button>Get started</Button>}>
            JSON Resume is a standard created to empower developers.
          </Feature>
          <Feature title="Themes" action={<Button>View themes</Button>}>
            Browse our gallery of resume themes made by the community.
          </Feature>
          <Feature title="Open Source" action={<Button>View on GitHub</Button>}>
            Every part of JSON Resume is open source on GitHub.
          </Feature>
        </Grid>
      </Container>
    </Section>
  );
}

Documentation page

A NavList beside Prose, inside a wide Container.

This styleguide is the reference implementation: a sticky NavList in a 14rem column and the article in the rest, collapsing to a single column below 992px.

Forms

Fields

Your resume is read from a gist named resume.json.

Enter an email address like name@example.com.

Show code
field/basic.tsx
import { Field, Input, Stack } from '@jsonresume/ui';
import * as styles from './basic.css';

export default function FieldBasic() {
  return (
    <Stack gap={5} className={styles.root}>
      <Field label="Full name" required>
        <Input autoComplete="name" />
      </Field>
      <Field
        label="GitHub username"
        hint="Your resume is read from a gist named resume.json."
      >
        <Input placeholder="thomasdavis" />
      </Field>
      <Field
        label="Email"
        error="Enter an email address like name@example.com."
      >
        <Input type="email" defaultValue="thomas@" />
      </Field>
    </Stack>
  );
}
field/basic.css.ts
import { style } from '@vanilla-extract/css';

export const root = style({ width: 'min(100%, 22rem)' });
  • One column, labels above controls, hints above the control.
  • Validate on submit, then on change for fields that have shown an error.
  • One primary button, on the end, named for the outcome.

Destructive actions

Confirm before deleting
Show code
dialog/confirm.tsx
'use client';

import {
  Button,
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogTitle,
  DialogTrigger,
} from '@jsonresume/ui';

export default function DialogConfirm() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="danger">Delete resume</Button>
      </DialogTrigger>
      <DialogContent>
        <DialogTitle>Delete your resume?</DialogTitle>
        <DialogDescription>
          Your gist stays on GitHub. This only removes the registry copy and its
          cached renders.
        </DialogDescription>
        <DialogFooter>
          <DialogClose asChild>
            <Button variant="ghost">Cancel</Button>
          </DialogClose>
          <DialogClose asChild>
            <Button variant="primary">Delete</Button>
          </DialogClose>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}