A reusable React component library for building coding playgrounds with Monaco editor integration, syntax highlighting, and test execution capabilities.
- 🎨 Monaco Editor Integration: Full-featured code editor with syntax highlighting, IntelliSense, and error checking
- 🔤 Multi-language Support: Built-in support for Python, JavaScript, C++, and Java
- ✅ Test Case Execution: Run and validate code against predefined test cases
- ⚡ Real-time Feedback: Instant feedback on code execution with detailed test results
- 📐 Split-panel Layout: Resizable panels for problem description, code editor, and results
- 📝 Markdown Support: Rich text rendering with math support (LaTeX/KaTeX)
- ⏱️ Built-in Timer: Track time spent on problems
- 🎭 Modern UI: Clean, dark theme with customizable components
- 📦 TypeScript: Full type safety and IntelliSense support
npm install coding-playground
# or
yarn add coding-playground
# or
pnpm add coding-playground
Make sure you have the following peer dependencies installed:
npm install react react-dom
import React from 'react';
import { Playground } from 'coding-playground';
import type { Problem } from 'coding-playground';
const problems: Problem[] = [
{
id: "two-sum",
title: "Two Sum",
description: "# Two Sum\n\nGiven an array of integers and a target sum, return indices of two numbers that add up to the target.",
functionSignature: "def two_sum(nums, target):",
testCases: [
{
input: "[2,7,11,15] 9",
expected: "[0,1]"
},
{
input: "[3,2,4] 6",
expected: "[1,2]"
}
]
}
];
function App() {
return (
<div className="h-screen">
<Playground problems={problems} />
</div>
);
}
export default App;
Here's a comprehensive example showing how to set up the coding playground with multiple problems and a custom execution handler:
import React from 'react';
import { Playground, Problem, ExecutionHandler } from 'coding-playground';
// Example problems data
const sampleProblems: Problem[] = [
{
id: "two-sum",
title: "Two Sum",
description: `# Two Sum
Given an array of integers \`nums\` and an integer \`target\`, return indices of the two numbers such that they add up to \`target\`.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
## Example 1:
- **Input:** nums = [2,7,11,15], target = 9
- **Output:** [0,1]
- **Explanation:** Because nums[0] + nums[1] == 9, we return [0, 1].
## Constraints:
- 2 ≤ nums.length ≤ 10^4
- -10^9 ≤ nums[i] ≤ 10^9
- -10^9 ≤ target ≤ 10^9`,
functionSignature: "def two_sum(nums, target):",
testCases: [
{ input: "[2,7,11,15] 9", expected: "[0,1]" },
{ input: "[3,2,4] 6", expected: "[1,2]" },
{ input: "[3,3] 6", expected: "[0,1]" }
]
},
{
id: "palindrome-check",
title: "Valid Palindrome",
description: `# Valid Palindrome
A phrase is a **palindrome** if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward.
Given a string \`s\`, return \`true\` if it is a palindrome, or \`false\` otherwise.
## Example 1:
- **Input:** s = "A man, a plan, a canal: Panama"
- **Output:** true
- **Explanation:** "amanaplanacanalpanama" is a palindrome.`,
functionSignature: "def is_palindrome(s):",
testCases: [
{ input: '"A man, a plan, a canal: Panama"', expected: 'true' },
{ input: '"race a car"', expected: 'false' },
{ input: '""', expected: 'true' }
]
}
];
// Example execution handler - in a real app, this would connect to your code execution backend
const handleExecution: ExecutionHandler = async (code, language, testCases, isSubmit) => {
// This is a mock implementation
// In a real app, you would send this to your backend service
console.log('Executing code:', { code, language, testCases, isSubmit });
// Simulate execution delay
await new Promise(resolve => setTimeout(resolve, 1000));
// Mock response - in reality, this would come from your code execution service
return {
stdout: 'Code executed successfully',
stderr: '',
exitCode: 0,
runtime: 150,
testResults: testCases.map((testCase, index) => ({
passed: index === 0, // Mock: first test passes, others fail
actual: index === 0 ? testCase.expected : 'Wrong answer'
}))
};
};
function App() {
return (
<div className="h-screen bg-slate-900 text-white">
{/* Include required CSS in your app:
- Tailwind CSS
- import 'katex/dist/katex.min.css';
- import 'highlight.js/styles/github-dark.css';
*/}
<Playground
problems={sampleProblems}
onExecute={handleExecution}
/>
</div>
);
}
export default App;
The main component that provides the complete coding playground experience.
import { Playground, Problem } from 'coding-playground';
interface PlaygroundProps {
problems: Problem[];
}
A standalone Monaco editor component.
import { CodeEditor } from 'coding-playground';
<CodeEditor
language="python"
value={code}
onChange={setCode}
height="400px"
/>
Render markdown content with syntax highlighting and math support.
import { MarkdownRenderer } from 'coding-playground';
<MarkdownRenderer
content="# Hello World\n\nThis supports **markdown** and $\\LaTeX$ math!"
/>
A simple timer component for tracking time.
import { Timer } from 'coding-playground';
<Timer />
interface Problem {
id: string;
title: string;
description: string; // Markdown content
testCases: TestCase[];
functionSignature: string; // Starting code template
}
interface TestCase {
input: string;
expected: string;
}
interface LanguageConfig {
name: string;
pistonLanguage: string; // For API execution
monacoLanguage: string; // For editor syntax highlighting
defaultCode: string;
}
The library comes with built-in support for:
import { LANGUAGES } from 'coding-playground';
// Available languages:
// - Python
// - JavaScript
// - C++
// - Java
Extend the language support by providing your own language configurations:
import { LanguageConfig } from 'coding-playground';
const customLanguage: LanguageConfig = {
name: 'Go',
pistonLanguage: 'go',
monacoLanguage: 'go',
defaultCode: 'package main\n\nfunc solve() int {\n // Your code here\n return 0\n}'
};
The library is built with Tailwind CSS and uses CSS variables for theming. Make sure to include Tailwind CSS in your project:
npm install -D tailwindcss
Import the required styles for syntax highlighting and math rendering:
/* In your main CSS file */
@import 'katex/dist/katex.min.css';
@import 'highlight.js/styles/github-dark.css';
Add the library paths to your Tailwind config:
// tailwind.config.js
module.exports = {
content: [
// ... your existing paths
'./node_modules/coding-playground/dist/**/*.{js,ts,jsx,tsx}',
],
// ... rest of your config
};
The library includes utilities for wrapping user code with test harnesses:
import { wrapCode, TestCase } from 'coding-playground';
const testCases: TestCase[] = [
{ input: "[1,2,3] 5", expected: "[1,4]" }
];
const wrappedCode = wrapCode('python', userCode, testCases);
// Execute wrappedCode with your preferred execution engine
Implement your own code execution logic:
interface ExecutionResult {
stdout: string;
stderr: string;
exitCode: number;
runtime: number;
testResults?: TestResult[];
}
// Implement your execution logic
const executeCode = async (
code: string,
language: string,
testCases: TestCase[]
): Promise<ExecutionResult> => {
// Your implementation here
};
Use individual components to build custom layouts:
import {
CodeEditor,
MarkdownRenderer,
Timer,
Button,
Tabs,
TabsContent,
TabsList,
TabsTrigger
} from 'coding-playground';
function CustomPlayground() {
return (
<div className="grid grid-cols-2 h-screen">
<div className="p-4">
<MarkdownRenderer content={problem.description} />
</div>
<div className="flex flex-col">
<div className="p-4 border-b flex justify-between">
<Button>Run Code</Button>
<Timer />
</div>
<CodeEditor
language="python"
value={code}
onChange={setCode}
/>
</div>
</div>
);
}
# Clone the repository
git clone https://github.com/aronnogh/coding-playground.git
cd coding-playground
# Install dependencies
npm install
# Build the library
npm run build
# The built files will be in the dist/ directory
- Fork the repository
- Create your feature branch:
git checkout -b feature/amazing-feature
- Commit your changes:
git commit -m 'Add some amazing feature'
- Push to the branch:
git push origin feature/amazing-feature
- Open a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Monaco Editor - The code editor that powers VS Code
- Radix UI - Unstyled, accessible UI components
- Tailwind CSS - Utility-first CSS framework
- React Markdown - Markdown component for React
- KaTeX - Fast math typesetting for the web
- Lucide React - Beautiful & consistent icon toolkit